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 "zbxserver.h"
22 #include "evalfunc.h"
23 #include "db.h"
24 #include "log.h"
25 #include "zbxalgo.h"
26 #include "valuecache.h"
27 #include "macrofunc.h"
28 #include "zbxregexp.h"
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/tree.h>
32 # include <libxml/xpath.h>
33 # include <libxml/xmlerror.h>
34
35 typedef struct
36 {
37 char *buf;
38 size_t len;
39 }
40 zbx_libxml_error_t;
41 #endif
42
43 /* The following definitions are used to identify the request field */
44 /* for various value getters grouped by their scope: */
45
46 /* DBget_item_value(), get_interface_value() */
47 #define ZBX_REQUEST_HOST_IP 1
48 #define ZBX_REQUEST_HOST_DNS 2
49 #define ZBX_REQUEST_HOST_CONN 3
50 #define ZBX_REQUEST_HOST_PORT 4
51
52 /* DBget_item_value() */
53 #define ZBX_REQUEST_HOST_ID 101
54 #define ZBX_REQUEST_HOST_HOST 102
55 #define ZBX_REQUEST_HOST_NAME 103
56 #define ZBX_REQUEST_HOST_DESCRIPTION 104
57 #define ZBX_REQUEST_ITEM_ID 105
58 #define ZBX_REQUEST_ITEM_NAME 106
59 #define ZBX_REQUEST_ITEM_NAME_ORIG 107
60 #define ZBX_REQUEST_ITEM_KEY 108
61 #define ZBX_REQUEST_ITEM_KEY_ORIG 109
62 #define ZBX_REQUEST_ITEM_DESCRIPTION 110
63 #define ZBX_REQUEST_PROXY_NAME 111
64 #define ZBX_REQUEST_PROXY_DESCRIPTION 112
65
66 /* DBget_history_log_value() */
67 #define ZBX_REQUEST_ITEM_LOG_DATE 201
68 #define ZBX_REQUEST_ITEM_LOG_TIME 202
69 #define ZBX_REQUEST_ITEM_LOG_AGE 203
70 #define ZBX_REQUEST_ITEM_LOG_SOURCE 204
71 #define ZBX_REQUEST_ITEM_LOG_SEVERITY 205
72 #define ZBX_REQUEST_ITEM_LOG_NSEVERITY 206
73 #define ZBX_REQUEST_ITEM_LOG_EVENTID 207
74
75 /******************************************************************************
76 * *
77 * Function: get_N_functionid *
78 * *
79 * Parameters: expression - [IN] null terminated trigger expression *
80 * '{11}=1 & {2346734}>5' *
81 * N_functionid - [IN] number of function in trigger expression *
82 * functionid - [OUT] ID of an N-th function in expression *
83 * end - [OUT] a pointer to text following the extracted *
84 * function id (can be NULL) *
85 * *
86 ******************************************************************************/
get_N_functionid(const char * expression,int N_functionid,zbx_uint64_t * functionid,const char ** end)87 int get_N_functionid(const char *expression, int N_functionid, zbx_uint64_t *functionid, const char **end)
88 {
89 enum state_t {NORMAL, ID} state = NORMAL;
90 int num = 0, ret = FAIL;
91 const char *c, *p_functionid = NULL;
92
93 for (c = expression; '\0' != *c; c++)
94 {
95 if ('{' == *c)
96 {
97 /* skip user macros */
98 if ('$' == c[1])
99 {
100 int macro_r, context_l, context_r;
101
102 if (SUCCEED == zbx_user_macro_parse(c, ¯o_r, &context_l, &context_r))
103 c += macro_r;
104 else
105 c++;
106
107 continue;
108 }
109
110 state = ID;
111 p_functionid = c + 1;
112 }
113 else if ('}' == *c && ID == state && NULL != p_functionid)
114 {
115 if (SUCCEED == is_uint64_n(p_functionid, c - p_functionid, functionid))
116 {
117 if (++num == N_functionid)
118 {
119 if (NULL != end)
120 *end = c + 1;
121
122 ret = SUCCEED;
123 break;
124 }
125 }
126
127 state = NORMAL;
128 }
129 }
130
131 return ret;
132 }
133
134 /******************************************************************************
135 * *
136 * Function: get_functionids *
137 * *
138 * Purpose: get identifiers of the functions used in expression *
139 * *
140 * Parameters: functionids - [OUT] the resulting vector of function ids *
141 * expression - [IN] null terminated trigger expression *
142 * '{11}=1 & {2346734}>5' *
143 * *
144 ******************************************************************************/
get_functionids(zbx_vector_uint64_t * functionids,const char * expression)145 void get_functionids(zbx_vector_uint64_t *functionids, const char *expression)
146 {
147 zbx_token_t token;
148 int pos = 0;
149 zbx_uint64_t functionid;
150
151 if ('\0' == *expression)
152 return;
153
154 for (; SUCCEED == zbx_token_find(expression, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
155 {
156 switch (token.type)
157 {
158 case ZBX_TOKEN_OBJECTID:
159 is_uint64_n(expression + token.loc.l + 1, token.loc.r - token.loc.l - 1,
160 &functionid);
161 zbx_vector_uint64_append(functionids, functionid);
162 ZBX_FALLTHROUGH;
163 case ZBX_TOKEN_USER_MACRO:
164 case ZBX_TOKEN_SIMPLE_MACRO:
165 case ZBX_TOKEN_MACRO:
166 pos = token.loc.r;
167 break;
168 }
169 }
170
171 zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
172 zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
173 }
174
175 /******************************************************************************
176 * *
177 * Function: get_N_itemid *
178 * *
179 * Parameters: expression - [IN] null terminated trigger expression *
180 * '{11}=1 & {2346734}>5' *
181 * N_functionid - [IN] number of function in trigger expression *
182 * itemid - [OUT] ID of an item of N-th function in *
183 * expression *
184 * *
185 ******************************************************************************/
get_N_itemid(const char * expression,int N_functionid,zbx_uint64_t * itemid)186 static int get_N_itemid(const char *expression, int N_functionid, zbx_uint64_t *itemid)
187 {
188 const char *__function_name = "get_N_itemid";
189
190 zbx_uint64_t functionid;
191 DC_FUNCTION function;
192 int errcode, ret = FAIL;
193
194 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s' N_functionid:%d",
195 __function_name, expression, N_functionid);
196
197 if (SUCCEED == get_N_functionid(expression, N_functionid, &functionid, NULL))
198 {
199 DCconfig_get_functions_by_functionids(&function, &functionid, &errcode, 1);
200
201 if (SUCCEED == errcode)
202 {
203 *itemid = function.itemid;
204 ret = SUCCEED;
205 }
206
207 DCconfig_clean_functions(&function, &errcode, 1);
208 }
209
210 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
211
212 return ret;
213 }
214
215 /******************************************************************************
216 * *
217 * Function: get_expanded_expression *
218 * *
219 * Purpose: get trigger expression with expanded user macros *
220 * *
221 * Comments: removes ' ', '\r', '\n' and '\t' for easier number search *
222 * *
223 ******************************************************************************/
get_expanded_expression(const char * expression)224 static char *get_expanded_expression(const char *expression)
225 {
226 char *expression_ex;
227
228 if (NULL != (expression_ex = DCexpression_expand_user_macros(expression)))
229 zbx_remove_whitespace(expression_ex);
230
231 return expression_ex;
232 }
233
234 /******************************************************************************
235 * *
236 * Function: get_trigger_expression_constant *
237 * *
238 * Purpose: get constant from a trigger expression corresponding a given *
239 * reference from trigger name *
240 * *
241 * Parameters: expression - [IN] trigger expression, source of constants *
242 * reference - [IN] reference from a trigger name ($1, $2, ...) *
243 * constant - [OUT] pointer to the constant's location in *
244 * trigger expression or empty string if there is *
245 * no corresponding constant *
246 * length - [OUT] length of constant *
247 * *
248 ******************************************************************************/
get_trigger_expression_constant(const char * expression,const zbx_token_reference_t * reference,const char ** constant,size_t * length)249 static void get_trigger_expression_constant(const char *expression, const zbx_token_reference_t *reference,
250 const char **constant, size_t *length)
251 {
252 size_t pos;
253 zbx_strloc_t number;
254 int index;
255
256 for (pos = 0, index = 1; SUCCEED == zbx_number_find(expression, pos, &number); pos = number.r + 1, index++)
257 {
258 if (index < reference->index)
259 continue;
260
261 *length = number.r - number.l + 1;
262 *constant = expression + number.l;
263 return;
264 }
265
266 *length = 0;
267 *constant = "";
268 }
269
DCexpand_trigger_expression(char ** expression)270 static void DCexpand_trigger_expression(char **expression)
271 {
272 const char *__function_name = "DCexpand_trigger_expression";
273
274 char *tmp = NULL;
275 size_t tmp_alloc = 256, tmp_offset = 0, l, r;
276 DC_FUNCTION function;
277 DC_ITEM item;
278 zbx_uint64_t functionid;
279 int errcode[2];
280
281 zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, *expression);
282
283 tmp = (char *)zbx_malloc(tmp, tmp_alloc);
284
285 for (l = 0; '\0' != (*expression)[l]; l++)
286 {
287 if ('{' != (*expression)[l])
288 {
289 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, (*expression)[l]);
290 continue;
291 }
292
293 /* skip user macros */
294 if ('$' == (*expression)[l + 1])
295 {
296 int macro_r, context_l, context_r;
297
298 if (SUCCEED == zbx_user_macro_parse(*expression + l, ¯o_r, &context_l, &context_r))
299 {
300 zbx_strncpy_alloc(&tmp, &tmp_alloc, &tmp_offset, *expression + l, macro_r + 1);
301 l += macro_r;
302 continue;
303 }
304
305 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '{');
306 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '$');
307 l++;
308 continue;
309 }
310
311 for (r = l + 1; 0 != isdigit((*expression)[r]); r++)
312 ;
313
314 if ('}' != (*expression)[r])
315 {
316 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, (*expression)[l]);
317 continue;
318 }
319
320 (*expression)[r] = '\0';
321
322 if (SUCCEED == is_uint64(&(*expression)[l + 1], &functionid))
323 {
324 DCconfig_get_functions_by_functionids(&function, &functionid, &errcode[0], 1);
325
326 if (SUCCEED == errcode[0])
327 {
328 DCconfig_get_items_by_itemids(&item, &function.itemid, &errcode[1], 1);
329
330 if (SUCCEED == errcode[1])
331 {
332 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '{');
333 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, item.host.host);
334 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ':');
335 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, item.key_orig);
336 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '.');
337 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, function.function);
338 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '(');
339 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, function.parameter);
340 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ")}");
341 }
342
343 DCconfig_clean_items(&item, &errcode[1], 1);
344 }
345
346 DCconfig_clean_functions(&function, &errcode[0], 1);
347
348 if (SUCCEED != errcode[0] || SUCCEED != errcode[1])
349 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, "*ERROR*");
350
351 l = r;
352 }
353 else
354 zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, (*expression)[l]);
355
356 (*expression)[r] = '}';
357 }
358
359 zbx_free(*expression);
360 *expression = tmp;
361
362 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __function_name, *expression);
363 }
364
365 /******************************************************************************
366 * *
367 * Function: get_trigger_severity_name *
368 * *
369 * Purpose: get trigger severity name *
370 * *
371 * Parameters: trigger - [IN] a trigger data with priority field; *
372 * TRIGGER_SEVERITY_* *
373 * replace_to - [OUT] pointer to a buffer that will receive *
374 * a null-terminated trigger severity string *
375 * *
376 * Return value: upon successful completion return SUCCEED *
377 * otherwise FAIL *
378 * *
379 ******************************************************************************/
get_trigger_severity_name(unsigned char priority,char ** replace_to)380 static int get_trigger_severity_name(unsigned char priority, char **replace_to)
381 {
382 zbx_config_t cfg;
383
384 if (TRIGGER_SEVERITY_COUNT <= priority)
385 return FAIL;
386
387 zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_SEVERITY_NAME);
388
389 *replace_to = zbx_strdup(*replace_to, cfg.severity_name[priority]);
390
391 zbx_config_clean(&cfg);
392
393 return SUCCEED;
394 }
395
396 /******************************************************************************
397 * *
398 * Function: get_problem_update_actions *
399 * *
400 * Purpose: get human readable list of problem update actions *
401 * *
402 * Parameters: ack - [IN] the acknowledge (problem update) data *
403 * actions - [IN] the required action flags *
404 * out - [OUT] the output buffer *
405 * *
406 * Return value: SUCCEED - successfully returned list of problem update *
407 * FAIL - no matching actions were made *
408 * *
409 ******************************************************************************/
get_problem_update_actions(const DB_ACKNOWLEDGE * ack,int actions,char ** out)410 static int get_problem_update_actions(const DB_ACKNOWLEDGE *ack, int actions, char **out)
411 {
412 char *buf = NULL, *prefixes[] = {"", ", ", ", ", ", "};
413 size_t buf_alloc = 0, buf_offset = 0;
414 int i, index, flags;
415
416 if (0 == (flags = ack->action & actions))
417 return FAIL;
418
419 for (i = 0, index = 0; i < ZBX_PROBLEM_UPDATE_ACTION_COUNT; i++)
420 {
421 if (0 != (flags & (1 << i)))
422 index++;
423 }
424
425 if (1 < index)
426 prefixes[index - 1] = " and ";
427
428 index = 0;
429
430 if (0 != (flags & ZBX_PROBLEM_UPDATE_ACKNOWLEDGE))
431 {
432 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "acknowledged");
433 index++;
434 }
435
436 if (0 != (flags & ZBX_PROBLEM_UPDATE_MESSAGE))
437 {
438 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
439 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "commented");
440 }
441
442 if (0 != (flags & ZBX_PROBLEM_UPDATE_SEVERITY))
443 {
444 zbx_config_t cfg;
445 const char *from = "unknown", *to = "unknown";
446
447 zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_SEVERITY_NAME);
448
449 if (TRIGGER_SEVERITY_COUNT > ack->old_severity && 0 <= ack->old_severity)
450 from = cfg.severity_name[ack->old_severity];
451
452 if (TRIGGER_SEVERITY_COUNT > ack->new_severity && 0 <= ack->new_severity)
453 to = cfg.severity_name[ack->new_severity];
454
455 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
456 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "changed severity from %s to %s",
457 from, to);
458
459 zbx_config_clean(&cfg);
460 }
461
462 if (0 != (flags & ZBX_PROBLEM_UPDATE_CLOSE))
463 {
464 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
465 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "closed");
466 }
467
468 zbx_free(*out);
469 *out = buf;
470
471 return SUCCEED;
472 }
473
474 /******************************************************************************
475 * *
476 * Function: item_description *
477 * *
478 * Purpose: substitute key parameters and user macros in *
479 * the item description string with real values *
480 * *
481 ******************************************************************************/
item_description(char ** data,const char * key,zbx_uint64_t hostid)482 static void item_description(char **data, const char *key, zbx_uint64_t hostid)
483 {
484 AGENT_REQUEST request;
485 const char *param;
486 char c, *p, *m, *n, *str_out = NULL, *replace_to = NULL;
487 int macro_r, context_l, context_r;
488
489 init_request(&request);
490
491 if (SUCCEED != parse_item_key(key, &request))
492 goto out;
493
494 p = *data;
495
496 while (NULL != (m = strchr(p, '$')))
497 {
498 if (m > p && '{' == *(m - 1) && FAIL != zbx_user_macro_parse(m - 1, ¯o_r, &context_l, &context_r))
499 {
500 /* user macros */
501
502 n = m + macro_r;
503 c = *n;
504 *n = '\0';
505 DCget_user_macro(&hostid, 1, m - 1, &replace_to);
506
507 if (NULL != replace_to)
508 {
509 *(m - 1) = '\0';
510 str_out = zbx_strdcat(str_out, p);
511 *(m - 1) = '{';
512
513 str_out = zbx_strdcat(str_out, replace_to);
514 zbx_free(replace_to);
515 }
516 else
517 str_out = zbx_strdcat(str_out, p);
518
519 *n = c;
520 p = n;
521 }
522 else if ('1' <= *(m + 1) && *(m + 1) <= '9')
523 {
524 /* macros $1, $2, ... */
525
526 *m = '\0';
527 str_out = zbx_strdcat(str_out, p);
528 *m++ = '$';
529
530 if (NULL != (param = get_rparam(&request, *m - '0' - 1)))
531 str_out = zbx_strdcat(str_out, param);
532
533 p = m + 1;
534 }
535 else
536 {
537 /* just a dollar sign */
538
539 c = *++m;
540 *m = '\0';
541 str_out = zbx_strdcat(str_out, p);
542 *m = c;
543 p = m;
544 }
545 }
546
547 if (NULL != str_out)
548 {
549 str_out = zbx_strdcat(str_out, p);
550 zbx_free(*data);
551 *data = str_out;
552 }
553 out:
554 free_request(&request);
555 }
556
557 /******************************************************************************
558 * *
559 * Function: DBget_host_value *
560 * *
561 * Purpose: request host name by hostid *
562 * *
563 * Return value: upon successful completion return SUCCEED *
564 * otherwise FAIL *
565 * *
566 ******************************************************************************/
DBget_host_value(zbx_uint64_t hostid,char ** replace_to,const char * field_name)567 static int DBget_host_value(zbx_uint64_t hostid, char **replace_to, const char *field_name)
568 {
569 DB_RESULT result;
570 DB_ROW row;
571 int ret = FAIL;
572
573 result = DBselect(
574 "select %s"
575 " from hosts"
576 " where hostid=" ZBX_FS_UI64,
577 field_name, hostid);
578
579 if (NULL != (row = DBfetch(result)))
580 {
581 *replace_to = zbx_strdup(*replace_to, row[0]);
582 ret = SUCCEED;
583 }
584 DBfree_result(result);
585
586 return ret;
587 }
588
589 /******************************************************************************
590 * *
591 * Function: DBget_templateid_by_triggerid *
592 * *
593 * Purpose: get template trigger ID from which the trigger is inherited *
594 * *
595 * Return value: upon successful completion return SUCCEED *
596 * otherwise FAIL *
597 * *
598 ******************************************************************************/
DBget_templateid_by_triggerid(zbx_uint64_t triggerid,zbx_uint64_t * templateid)599 static int DBget_templateid_by_triggerid(zbx_uint64_t triggerid, zbx_uint64_t *templateid)
600 {
601 DB_RESULT result;
602 DB_ROW row;
603 int ret = FAIL;
604
605 result = DBselect(
606 "select templateid"
607 " from triggers"
608 " where triggerid=" ZBX_FS_UI64,
609 triggerid);
610
611 if (NULL != (row = DBfetch(result)))
612 {
613 ZBX_DBROW2UINT64(*templateid, row[0]);
614 ret = SUCCEED;
615 }
616 DBfree_result(result);
617
618 return ret;
619 }
620
621 /******************************************************************************
622 * *
623 * Function: DBget_trigger_template_name *
624 * *
625 * Purpose: get comma-space separated trigger template names in which *
626 * the trigger is defined *
627 * *
628 * Return value: upon successful completion return SUCCEED *
629 * otherwise FAIL *
630 * *
631 * Comments: based on the patch submitted by Hmami Mohamed *
632 * *
633 ******************************************************************************/
DBget_trigger_template_name(zbx_uint64_t triggerid,const zbx_uint64_t * userid,char ** replace_to)634 static int DBget_trigger_template_name(zbx_uint64_t triggerid, const zbx_uint64_t *userid, char **replace_to)
635 {
636 const char *__function_name = "DBget_trigger_template_name";
637
638 DB_RESULT result;
639 DB_ROW row;
640 int ret = FAIL;
641 zbx_uint64_t templateid;
642 char *sql = NULL;
643 size_t replace_to_alloc = 64, replace_to_offset = 0,
644 sql_alloc = 256, sql_offset = 0;
645 int user_type = -1;
646
647 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
648
649 if (NULL != userid)
650 {
651 result = DBselect("select type from users where userid=" ZBX_FS_UI64, *userid);
652
653 if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
654 user_type = atoi(row[0]);
655 DBfree_result(result);
656
657 if (-1 == user_type)
658 {
659 zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __function_name);
660 goto out;
661 }
662 }
663
664 /* use parent trigger ID for lld generated triggers */
665 result = DBselect(
666 "select parent_triggerid"
667 " from trigger_discovery"
668 " where triggerid=" ZBX_FS_UI64,
669 triggerid);
670
671 if (NULL != (row = DBfetch(result)))
672 ZBX_STR2UINT64(triggerid, row[0]);
673 DBfree_result(result);
674
675 if (SUCCEED != DBget_templateid_by_triggerid(triggerid, &templateid) || 0 == templateid)
676 {
677 zabbix_log(LOG_LEVEL_DEBUG, "%s() trigger not found or not templated", __function_name);
678 goto out;
679 }
680
681 do
682 {
683 triggerid = templateid;
684 }
685 while (SUCCEED == (ret = DBget_templateid_by_triggerid(triggerid, &templateid)) && 0 != templateid);
686
687 if (SUCCEED != ret)
688 {
689 zabbix_log(LOG_LEVEL_DEBUG, "%s() trigger not found", __function_name);
690 goto out;
691 }
692
693 *replace_to = (char *)zbx_realloc(*replace_to, replace_to_alloc);
694 **replace_to = '\0';
695
696 sql = (char *)zbx_malloc(sql, sql_alloc);
697
698 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
699 "select distinct h.name"
700 " from hosts h,items i,functions f"
701 " where h.hostid=i.hostid"
702 " and i.itemid=f.itemid"
703 " and f.triggerid=" ZBX_FS_UI64,
704 triggerid);
705 if (NULL != userid && USER_TYPE_SUPER_ADMIN != user_type)
706 {
707 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
708 " and exists("
709 "select null"
710 " from hosts_groups hg,rights r,users_groups ug"
711 " where h.hostid=hg.hostid"
712 " and hg.groupid=r.id"
713 " and r.groupid=ug.usrgrpid"
714 " and ug.userid=" ZBX_FS_UI64
715 " group by hg.hostid"
716 " having min(r.permission)>=%d"
717 ")",
718 *userid, PERM_READ);
719 }
720 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by h.name");
721
722 result = DBselect("%s", sql);
723
724 zbx_free(sql);
725
726 while (NULL != (row = DBfetch(result)))
727 {
728 if (0 != replace_to_offset)
729 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
730 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, row[0]);
731 }
732 DBfree_result(result);
733 out:
734 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
735
736 return ret;
737 }
738
739 /******************************************************************************
740 * *
741 * Function: DBget_trigger_hostgroup_name *
742 * *
743 * Purpose: get comma-space separated host group names in which the trigger *
744 * is defined *
745 * *
746 * Return value: upon successful completion return SUCCEED *
747 * otherwise FAIL *
748 * *
749 ******************************************************************************/
DBget_trigger_hostgroup_name(zbx_uint64_t triggerid,const zbx_uint64_t * userid,char ** replace_to)750 static int DBget_trigger_hostgroup_name(zbx_uint64_t triggerid, const zbx_uint64_t *userid, char **replace_to)
751 {
752 const char *__function_name = "DBget_trigger_hostgroup_name";
753
754 DB_RESULT result;
755 DB_ROW row;
756 int ret = FAIL;
757 char *sql = NULL;
758 size_t replace_to_alloc = 64, replace_to_offset = 0,
759 sql_alloc = 256, sql_offset = 0;
760 int user_type = -1;
761
762 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
763
764 if (NULL != userid)
765 {
766 result = DBselect("select type from users where userid=" ZBX_FS_UI64, *userid);
767
768 if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
769 user_type = atoi(row[0]);
770 DBfree_result(result);
771
772 if (-1 == user_type)
773 {
774 zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __function_name);
775 goto out;
776 }
777 }
778
779 *replace_to = (char *)zbx_realloc(*replace_to, replace_to_alloc);
780 **replace_to = '\0';
781
782 sql = (char *)zbx_malloc(sql, sql_alloc);
783
784 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
785 "select distinct g.name"
786 " from hstgrp g,hosts_groups hg,items i,functions f"
787 " where g.groupid=hg.groupid"
788 " and hg.hostid=i.hostid"
789 " and i.itemid=f.itemid"
790 " and f.triggerid=" ZBX_FS_UI64,
791 triggerid);
792 if (NULL != userid && USER_TYPE_SUPER_ADMIN != user_type)
793 {
794 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
795 " and exists("
796 "select null"
797 " from rights r,users_groups ug"
798 " where g.groupid=r.id"
799 " and r.groupid=ug.usrgrpid"
800 " and ug.userid=" ZBX_FS_UI64
801 " group by r.id"
802 " having min(r.permission)>=%d"
803 ")",
804 *userid, PERM_READ);
805 }
806 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by g.name");
807
808 result = DBselect("%s", sql);
809
810 zbx_free(sql);
811
812 while (NULL != (row = DBfetch(result)))
813 {
814 if (0 != replace_to_offset)
815 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
816 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, row[0]);
817 ret = SUCCEED;
818 }
819 DBfree_result(result);
820 out:
821 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
822
823 return ret;
824 }
825
826 /******************************************************************************
827 * *
828 * Function: get_interface_value *
829 * *
830 * Purpose: retrieve a particular value associated with the interface *
831 * *
832 * Return value: upon successful completion return SUCCEED *
833 * otherwise FAIL *
834 * *
835 ******************************************************************************/
get_interface_value(zbx_uint64_t hostid,zbx_uint64_t itemid,char ** replace_to,int request)836 static int get_interface_value(zbx_uint64_t hostid, zbx_uint64_t itemid, char **replace_to, int request)
837 {
838 int res;
839 DC_INTERFACE interface;
840
841 if (SUCCEED != (res = DCconfig_get_interface(&interface, hostid, itemid)))
842 return res;
843
844 switch (request)
845 {
846 case ZBX_REQUEST_HOST_IP:
847 *replace_to = zbx_strdup(*replace_to, interface.ip_orig);
848 break;
849 case ZBX_REQUEST_HOST_DNS:
850 *replace_to = zbx_strdup(*replace_to, interface.dns_orig);
851 break;
852 case ZBX_REQUEST_HOST_CONN:
853 *replace_to = zbx_strdup(*replace_to, interface.addr);
854 break;
855 case ZBX_REQUEST_HOST_PORT:
856 *replace_to = zbx_strdup(*replace_to, interface.port_orig);
857 break;
858 default:
859 THIS_SHOULD_NEVER_HAPPEN;
860 res = FAIL;
861 }
862
863 return res;
864 }
865
get_host_value(zbx_uint64_t itemid,char ** replace_to,int request)866 static int get_host_value(zbx_uint64_t itemid, char **replace_to, int request)
867 {
868 int ret;
869 DC_HOST host;
870
871 DCconfig_get_hosts_by_itemids(&host, &itemid, &ret, 1);
872
873 if (FAIL == ret)
874 return FAIL;
875
876 switch (request)
877 {
878 case ZBX_REQUEST_HOST_ID:
879 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, host.hostid);
880 break;
881 case ZBX_REQUEST_HOST_HOST:
882 *replace_to = zbx_strdup(*replace_to, host.host);
883 break;
884 case ZBX_REQUEST_HOST_NAME:
885 *replace_to = zbx_strdup(*replace_to, host.name);
886 break;
887 default:
888 THIS_SHOULD_NEVER_HAPPEN;
889 ret = FAIL;
890 }
891
892 return ret;
893 }
894
895 /******************************************************************************
896 * *
897 * Function: zbx_substitute_item_name_macros *
898 * *
899 * Purpose: substitute key macros and use it to substitute item name macros if*
900 * item name is specified *
901 * *
902 * Parameters: dc_item - [IN] item information used in substitution *
903 * name - [IN] optional item name to substitute *
904 * replace_to - [OUT] expanded item name or key if name is absent *
905 * *
906 ******************************************************************************/
zbx_substitute_item_name_macros(DC_ITEM * dc_item,const char * name,char ** replace_to)907 int zbx_substitute_item_name_macros(DC_ITEM *dc_item, const char *name, char **replace_to)
908 {
909 int ret;
910 char *key;
911
912 if (INTERFACE_TYPE_UNKNOWN == dc_item->interface.type)
913 ret = DCconfig_get_interface(&dc_item->interface, dc_item->host.hostid, 0);
914 else
915 ret = SUCCEED;
916
917 if (ret == FAIL)
918 return FAIL;
919
920 key = zbx_strdup(NULL, dc_item->key_orig);
921 substitute_key_macros(&key, NULL, dc_item, NULL, MACRO_TYPE_ITEM_KEY,
922 NULL, 0);
923
924 if (NULL != name)
925 {
926 *replace_to = zbx_strdup(*replace_to, name);
927 item_description(replace_to, key, dc_item->host.hostid);
928 zbx_free(key);
929 }
930 else /* ZBX_REQUEST_ITEM_KEY */
931 {
932 zbx_free(*replace_to);
933 *replace_to = key;
934 }
935
936 return ret;
937 }
938
939 /******************************************************************************
940 * *
941 * Function: DBget_item_value *
942 * *
943 * Purpose: retrieve a particular value associated with the item *
944 * *
945 * Return value: upon successful completion return SUCCEED *
946 * otherwise FAIL *
947 * *
948 ******************************************************************************/
DBget_item_value(zbx_uint64_t itemid,char ** replace_to,int request)949 static int DBget_item_value(zbx_uint64_t itemid, char **replace_to, int request)
950 {
951 const char *__function_name = "DBget_item_value";
952 DB_RESULT result;
953 DB_ROW row;
954 DC_ITEM dc_item;
955 zbx_uint64_t proxy_hostid;
956 int ret = FAIL, errcode;
957
958 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
959
960 switch (request)
961 {
962 case ZBX_REQUEST_HOST_IP:
963 case ZBX_REQUEST_HOST_DNS:
964 case ZBX_REQUEST_HOST_CONN:
965 case ZBX_REQUEST_HOST_PORT:
966 return get_interface_value(0, itemid, replace_to, request);
967 case ZBX_REQUEST_HOST_ID:
968 case ZBX_REQUEST_HOST_HOST:
969 case ZBX_REQUEST_HOST_NAME:
970 return get_host_value(itemid, replace_to, request);
971 }
972
973 result = DBselect(
974 "select h.proxy_hostid,h.description,i.itemid,i.name,i.key_,i.description"
975 " from items i"
976 " join hosts h on h.hostid=i.hostid"
977 " where i.itemid=" ZBX_FS_UI64, itemid);
978
979 if (NULL != (row = DBfetch(result)))
980 {
981 switch (request)
982 {
983 case ZBX_REQUEST_HOST_DESCRIPTION:
984 *replace_to = zbx_strdup(*replace_to, row[1]);
985 ret = SUCCEED;
986 break;
987 case ZBX_REQUEST_ITEM_ID:
988 *replace_to = zbx_strdup(*replace_to, row[2]);
989 ret = SUCCEED;
990 break;
991 case ZBX_REQUEST_ITEM_NAME:
992 DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
993
994 if (SUCCEED == errcode)
995 ret = zbx_substitute_item_name_macros(&dc_item, row[3], replace_to);
996
997 DCconfig_clean_items(&dc_item, &errcode, 1);
998 break;
999 case ZBX_REQUEST_ITEM_KEY:
1000 DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
1001
1002 if (SUCCEED == errcode)
1003 ret = zbx_substitute_item_name_macros(&dc_item, NULL, replace_to);
1004
1005 DCconfig_clean_items(&dc_item, &errcode, 1);
1006 break;
1007 case ZBX_REQUEST_ITEM_NAME_ORIG:
1008 *replace_to = zbx_strdup(*replace_to, row[3]);
1009 ret = SUCCEED;
1010 break;
1011 case ZBX_REQUEST_ITEM_KEY_ORIG:
1012 *replace_to = zbx_strdup(*replace_to, row[4]);
1013 ret = SUCCEED;
1014 break;
1015 case ZBX_REQUEST_ITEM_DESCRIPTION:
1016 *replace_to = zbx_strdup(*replace_to, row[5]);
1017 ret = SUCCEED;
1018 break;
1019 case ZBX_REQUEST_PROXY_NAME:
1020 ZBX_DBROW2UINT64(proxy_hostid, row[0]);
1021
1022 if (0 == proxy_hostid)
1023 {
1024 *replace_to = zbx_strdup(*replace_to, "");
1025 ret = SUCCEED;
1026 }
1027 else
1028 ret = DBget_host_value(proxy_hostid, replace_to, "host");
1029 break;
1030 case ZBX_REQUEST_PROXY_DESCRIPTION:
1031 ZBX_DBROW2UINT64(proxy_hostid, row[0]);
1032
1033 if (0 == proxy_hostid)
1034 {
1035 *replace_to = zbx_strdup(*replace_to, "");
1036 ret = SUCCEED;
1037 }
1038 else
1039 ret = DBget_host_value(proxy_hostid, replace_to, "description");
1040 break;
1041 }
1042 }
1043 DBfree_result(result);
1044
1045 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1046
1047 return ret;
1048 }
1049
1050 /******************************************************************************
1051 * *
1052 * Function: DBget_trigger_value *
1053 * *
1054 * Purpose: retrieve a particular value associated with the trigger's *
1055 * N_functionid'th function *
1056 * *
1057 * Return value: upon successful completion return SUCCEED *
1058 * otherwise FAIL *
1059 * *
1060 ******************************************************************************/
DBget_trigger_value(const char * expression,char ** replace_to,int N_functionid,int request)1061 static int DBget_trigger_value(const char *expression, char **replace_to, int N_functionid, int request)
1062 {
1063 const char *__function_name = "DBget_trigger_value";
1064
1065 zbx_uint64_t itemid;
1066 int ret = FAIL;
1067
1068 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1069
1070 if (SUCCEED == get_N_itemid(expression, N_functionid, &itemid))
1071 ret = DBget_item_value(itemid, replace_to, request);
1072
1073 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1074
1075 return ret;
1076 }
1077
1078 /******************************************************************************
1079 * *
1080 * Function: DBget_trigger_event_count *
1081 * *
1082 * Purpose: retrieve number of events (acknowledged or unacknowledged) for a *
1083 * trigger (in an OK or PROBLEM state) which generated an event *
1084 * *
1085 * Parameters: triggerid - [IN] trigger identifier from database *
1086 * replace_to - [IN/OUT] pointer to result buffer *
1087 * problem_only - [IN] selected trigger status: *
1088 * 0 - TRIGGER_VALUE_PROBLEM and TRIGGER_VALUE_OK *
1089 * 1 - TRIGGER_VALUE_PROBLEM *
1090 * acknowledged - [IN] acknowledged event or not *
1091 * *
1092 * Return value: upon successful completion return SUCCEED *
1093 * otherwise FAIL *
1094 * *
1095 * Author: Alexander Vladishev, Aleksandrs Saveljevs *
1096 * *
1097 * Comments: *
1098 * *
1099 ******************************************************************************/
DBget_trigger_event_count(zbx_uint64_t triggerid,char ** replace_to,int problem_only,int acknowledged)1100 static int DBget_trigger_event_count(zbx_uint64_t triggerid, char **replace_to, int problem_only, int acknowledged)
1101 {
1102 DB_RESULT result;
1103 DB_ROW row;
1104 char value[4];
1105 int ret = FAIL;
1106
1107 if (problem_only)
1108 zbx_snprintf(value, sizeof(value), "%d", TRIGGER_VALUE_PROBLEM);
1109 else
1110 zbx_snprintf(value, sizeof(value), "%d,%d", TRIGGER_VALUE_PROBLEM, TRIGGER_VALUE_OK);
1111
1112 result = DBselect(
1113 "select count(*)"
1114 " from events"
1115 " where source=%d"
1116 " and object=%d"
1117 " and objectid=" ZBX_FS_UI64
1118 " and value in (%s)"
1119 " and acknowledged=%d",
1120 EVENT_SOURCE_TRIGGERS,
1121 EVENT_OBJECT_TRIGGER,
1122 triggerid,
1123 value,
1124 acknowledged);
1125
1126 if (NULL != (row = DBfetch(result)))
1127 {
1128 *replace_to = zbx_strdup(*replace_to, row[0]);
1129 ret = SUCCEED;
1130 }
1131 DBfree_result(result);
1132
1133 return ret;
1134 }
1135
1136 /******************************************************************************
1137 * *
1138 * Function: DBget_dhost_value_by_event *
1139 * *
1140 * Purpose: retrieve discovered host value by event and field name *
1141 * *
1142 * Parameters: *
1143 * *
1144 * Return value: upon successful completion return SUCCEED *
1145 * otherwise FAIL *
1146 * *
1147 * Author: Alexander Vladishev *
1148 * *
1149 * Comments: *
1150 * *
1151 ******************************************************************************/
DBget_dhost_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1152 static int DBget_dhost_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1153 {
1154 DB_RESULT result;
1155 DB_ROW row;
1156 int ret = FAIL;
1157 char sql[MAX_STRING_LEN];
1158
1159 switch (event->object)
1160 {
1161 case EVENT_OBJECT_DHOST:
1162 zbx_snprintf(sql, sizeof(sql),
1163 "select %s"
1164 " from drules r,dhosts h,dservices s"
1165 " where r.druleid=h.druleid"
1166 " and h.dhostid=s.dhostid"
1167 " and h.dhostid=" ZBX_FS_UI64
1168 " order by s.dserviceid",
1169 fieldname,
1170 event->objectid);
1171 break;
1172 case EVENT_OBJECT_DSERVICE:
1173 zbx_snprintf(sql, sizeof(sql),
1174 "select %s"
1175 " from drules r,dhosts h,dservices s"
1176 " where r.druleid=h.druleid"
1177 " and h.dhostid=s.dhostid"
1178 " and s.dserviceid=" ZBX_FS_UI64,
1179 fieldname,
1180 event->objectid);
1181 break;
1182 default:
1183 return ret;
1184 }
1185
1186 result = DBselectN(sql, 1);
1187
1188 if (NULL != (row = DBfetch(result)))
1189 {
1190 *replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1191 ret = SUCCEED;
1192 }
1193 DBfree_result(result);
1194
1195 return ret;
1196 }
1197
1198 /******************************************************************************
1199 * *
1200 * Function: DBget_dchecks_value_by_event *
1201 * *
1202 * Purpose: retrieve discovery rule check value by event and field name *
1203 * *
1204 * Return value: upon successful completion return SUCCEED *
1205 * otherwise FAIL *
1206 * *
1207 ******************************************************************************/
DBget_dchecks_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1208 static int DBget_dchecks_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1209 {
1210 DB_RESULT result;
1211 DB_ROW row;
1212 int ret = FAIL;
1213
1214 switch (event->object)
1215 {
1216 case EVENT_OBJECT_DSERVICE:
1217 result = DBselect("select %s from dchecks c,dservices s"
1218 " where c.dcheckid=s.dcheckid and s.dserviceid=" ZBX_FS_UI64,
1219 fieldname, event->objectid);
1220 break;
1221 default:
1222 return ret;
1223 }
1224
1225 if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
1226 {
1227 *replace_to = zbx_strdup(*replace_to, row[0]);
1228 ret = SUCCEED;
1229 }
1230 DBfree_result(result);
1231
1232 return ret;
1233 }
1234
1235 /******************************************************************************
1236 * *
1237 * Function: DBget_dservice_value_by_event *
1238 * *
1239 * Purpose: retrieve discovered service value by event and field name *
1240 * *
1241 * Parameters: *
1242 * *
1243 * Return value: upon successful completion return SUCCEED *
1244 * otherwise FAIL *
1245 * *
1246 * Author: Alexander Vladishev *
1247 * *
1248 * Comments: *
1249 * *
1250 ******************************************************************************/
DBget_dservice_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1251 static int DBget_dservice_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1252 {
1253 DB_RESULT result;
1254 DB_ROW row;
1255 int ret = FAIL;
1256
1257 switch (event->object)
1258 {
1259 case EVENT_OBJECT_DSERVICE:
1260 result = DBselect("select %s from dservices s where s.dserviceid=" ZBX_FS_UI64,
1261 fieldname, event->objectid);
1262 break;
1263 default:
1264 return ret;
1265 }
1266
1267 if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
1268 {
1269 *replace_to = zbx_strdup(*replace_to, row[0]);
1270 ret = SUCCEED;
1271 }
1272 DBfree_result(result);
1273
1274 return ret;
1275 }
1276
1277 /******************************************************************************
1278 * *
1279 * Function: DBget_drule_value_by_event *
1280 * *
1281 * Purpose: retrieve discovery rule value by event and field name *
1282 * *
1283 * Parameters: *
1284 * *
1285 * Return value: upon successful completion return SUCCEED *
1286 * otherwise FAIL *
1287 * *
1288 * Author: Alexander Vladishev *
1289 * *
1290 * Comments: *
1291 * *
1292 ******************************************************************************/
DBget_drule_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1293 static int DBget_drule_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1294 {
1295 DB_RESULT result;
1296 DB_ROW row;
1297 int ret = FAIL;
1298
1299 if (EVENT_SOURCE_DISCOVERY != event->source)
1300 return FAIL;
1301
1302 switch (event->object)
1303 {
1304 case EVENT_OBJECT_DHOST:
1305 result = DBselect("select r.%s from drules r,dhosts h"
1306 " where r.druleid=h.druleid and h.dhostid=" ZBX_FS_UI64,
1307 fieldname, event->objectid);
1308 break;
1309 case EVENT_OBJECT_DSERVICE:
1310 result = DBselect("select r.%s from drules r,dhosts h,dservices s"
1311 " where r.druleid=h.druleid and h.dhostid=s.dhostid and s.dserviceid=" ZBX_FS_UI64,
1312 fieldname, event->objectid);
1313 break;
1314 default:
1315 return ret;
1316 }
1317
1318 if (NULL != (row = DBfetch(result)))
1319 {
1320 *replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1321 ret = SUCCEED;
1322 }
1323 DBfree_result(result);
1324
1325 return ret;
1326 }
1327
1328 /******************************************************************************
1329 * *
1330 * Function: DBget_history_log_value *
1331 * *
1332 * Purpose: retrieve a particular attribute of a log value *
1333 * *
1334 * Return value: upon successful completion return SUCCEED *
1335 * otherwise FAIL *
1336 * *
1337 ******************************************************************************/
DBget_history_log_value(zbx_uint64_t itemid,char ** replace_to,int request,int clock,int ns)1338 static int DBget_history_log_value(zbx_uint64_t itemid, char **replace_to, int request, int clock, int ns)
1339 {
1340 const char *__function_name = "DBget_history_log_value";
1341
1342 DC_ITEM item;
1343 int ret = FAIL, errcode = FAIL;
1344 zbx_timespec_t ts = {clock, ns};
1345 zbx_history_record_t value;
1346
1347 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1348
1349 DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
1350
1351 if (SUCCEED != errcode || ITEM_VALUE_TYPE_LOG != item.value_type)
1352 goto out;
1353
1354 if (SUCCEED != zbx_vc_get_value(itemid, item.value_type, &ts, &value))
1355 goto out;
1356
1357 switch (request)
1358 {
1359 case ZBX_REQUEST_ITEM_LOG_DATE:
1360 *replace_to = zbx_strdup(*replace_to, zbx_date2str((time_t)value.value.log->timestamp));
1361 goto success;
1362 case ZBX_REQUEST_ITEM_LOG_TIME:
1363 *replace_to = zbx_strdup(*replace_to, zbx_time2str((time_t)value.value.log->timestamp));
1364 goto success;
1365 case ZBX_REQUEST_ITEM_LOG_AGE:
1366 *replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - value.value.log->timestamp));
1367 goto success;
1368 }
1369
1370 /* the following attributes are set only for windows eventlog items */
1371 if (0 != strncmp(item.key_orig, "eventlog[", 9))
1372 goto clean;
1373
1374 switch (request)
1375 {
1376 case ZBX_REQUEST_ITEM_LOG_SOURCE:
1377 *replace_to = zbx_strdup(*replace_to, (NULL == value.value.log->source ? "" :
1378 value.value.log->source));
1379 break;
1380 case ZBX_REQUEST_ITEM_LOG_SEVERITY:
1381 *replace_to = zbx_strdup(*replace_to,
1382 zbx_item_logtype_string((unsigned char)value.value.log->severity));
1383 break;
1384 case ZBX_REQUEST_ITEM_LOG_NSEVERITY:
1385 *replace_to = zbx_dsprintf(*replace_to, "%d", value.value.log->severity);
1386 break;
1387 case ZBX_REQUEST_ITEM_LOG_EVENTID:
1388 *replace_to = zbx_dsprintf(*replace_to, "%d", value.value.log->logeventid);
1389 break;
1390 }
1391 success:
1392 ret = SUCCEED;
1393 clean:
1394 zbx_history_record_clear(&value, ITEM_VALUE_TYPE_LOG);
1395 out:
1396 DCconfig_clean_items(&item, &errcode, 1);
1397
1398 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1399
1400 return ret;
1401 }
1402
1403 /******************************************************************************
1404 * *
1405 * Function: get_history_log_value *
1406 * *
1407 * Purpose: retrieve a particular attribute of a log value *
1408 * *
1409 * Return value: upon successful completion return SUCCEED *
1410 * otherwise FAIL *
1411 * *
1412 ******************************************************************************/
get_history_log_value(const char * expression,char ** replace_to,int N_functionid,int request,int clock,int ns)1413 static int get_history_log_value(const char *expression, char **replace_to, int N_functionid,
1414 int request, int clock, int ns)
1415 {
1416 const char *__function_name = "get_history_log_value";
1417
1418 zbx_uint64_t itemid;
1419 int ret = FAIL;
1420
1421 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1422
1423 if (SUCCEED == get_N_itemid(expression, N_functionid, &itemid))
1424 ret = DBget_history_log_value(itemid, replace_to, request, clock, ns);
1425
1426 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1427
1428 return ret;
1429 }
1430
1431 /******************************************************************************
1432 * *
1433 * Function: DBitem_lastvalue *
1434 * *
1435 * Purpose: retrieve item lastvalue by trigger expression *
1436 * and number of function *
1437 * *
1438 * Parameters: *
1439 * *
1440 * Return value: upon successful completion return SUCCEED *
1441 * otherwise FAIL *
1442 * *
1443 * Author: Alexander Vladishev *
1444 * *
1445 * Comments: *
1446 * *
1447 ******************************************************************************/
DBitem_lastvalue(const char * expression,char ** lastvalue,int N_functionid,int raw)1448 static int DBitem_lastvalue(const char *expression, char **lastvalue, int N_functionid, int raw)
1449 {
1450 const char *__function_name = "DBitem_lastvalue";
1451
1452 DB_RESULT result;
1453 DB_ROW row;
1454 zbx_uint64_t itemid;
1455 int ret = FAIL;
1456
1457 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1458
1459 if (FAIL == get_N_itemid(expression, N_functionid, &itemid))
1460 goto out;
1461
1462 result = DBselect(
1463 "select value_type,valuemapid,units"
1464 " from items"
1465 " where itemid=" ZBX_FS_UI64,
1466 itemid);
1467
1468 if (NULL != (row = DBfetch(result)))
1469 {
1470 unsigned char value_type;
1471 zbx_uint64_t valuemapid;
1472 zbx_history_record_t vc_value;
1473 zbx_timespec_t ts;
1474
1475 ts.sec = time(NULL);
1476 ts.ns = 999999999;
1477
1478 value_type = (unsigned char)atoi(row[0]);
1479 ZBX_DBROW2UINT64(valuemapid, row[1]);
1480
1481 if (SUCCEED == zbx_vc_get_value(itemid, value_type, &ts, &vc_value))
1482 {
1483 char tmp[MAX_BUFFER_LEN];
1484
1485 zbx_history_value2str(tmp, sizeof(tmp), &vc_value.value, value_type);
1486 zbx_history_record_clear(&vc_value, value_type);
1487
1488 if (0 == raw)
1489 zbx_format_value(tmp, sizeof(tmp), valuemapid, row[2], value_type);
1490
1491 *lastvalue = zbx_strdup(*lastvalue, tmp);
1492
1493 ret = SUCCEED;
1494 }
1495 }
1496 DBfree_result(result);
1497 out:
1498 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1499
1500 return ret;
1501 }
1502
1503 /******************************************************************************
1504 * *
1505 * Function: DBitem_value *
1506 * *
1507 * Purpose: retrieve item value by trigger expression and number of function *
1508 * *
1509 * Return value: upon successful completion return SUCCEED *
1510 * otherwise FAIL *
1511 * *
1512 ******************************************************************************/
DBitem_value(const char * expression,char ** value,int N_functionid,int clock,int ns,int raw)1513 static int DBitem_value(const char *expression, char **value, int N_functionid, int clock, int ns, int raw)
1514 {
1515 const char *__function_name = "DBitem_value";
1516
1517 DB_RESULT result;
1518 DB_ROW row;
1519 zbx_uint64_t itemid;
1520 int ret = FAIL;
1521
1522 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1523
1524 if (FAIL == get_N_itemid(expression, N_functionid, &itemid))
1525 goto out;
1526
1527 result = DBselect(
1528 "select value_type,valuemapid,units"
1529 " from items"
1530 " where itemid=" ZBX_FS_UI64,
1531 itemid);
1532
1533 if (NULL != (row = DBfetch(result)))
1534 {
1535 unsigned char value_type;
1536 zbx_uint64_t valuemapid;
1537 zbx_timespec_t ts = {clock, ns};
1538 zbx_history_record_t vc_value;
1539
1540 value_type = (unsigned char)atoi(row[0]);
1541 ZBX_DBROW2UINT64(valuemapid, row[1]);
1542
1543 if (SUCCEED == zbx_vc_get_value(itemid, value_type, &ts, &vc_value))
1544 {
1545 char tmp[MAX_BUFFER_LEN];
1546
1547 zbx_history_value2str(tmp, sizeof(tmp), &vc_value.value, value_type);
1548 zbx_history_record_clear(&vc_value, value_type);
1549
1550 if (0 == raw)
1551 zbx_format_value(tmp, sizeof(tmp), valuemapid, row[2], value_type);
1552
1553 *value = zbx_strdup(*value, tmp);
1554
1555 ret = SUCCEED;
1556 }
1557 }
1558 DBfree_result(result);
1559 out:
1560 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1561
1562 return ret;
1563 }
1564
1565 /******************************************************************************
1566 * *
1567 * Function: get_escalation_history *
1568 * *
1569 * Purpose: retrieve escalation history *
1570 * *
1571 ******************************************************************************/
get_escalation_history(zbx_uint64_t actionid,const DB_EVENT * event,const DB_EVENT * r_event,char ** replace_to,const zbx_uint64_t * recipient_userid)1572 static void get_escalation_history(zbx_uint64_t actionid, const DB_EVENT *event, const DB_EVENT *r_event,
1573 char **replace_to, const zbx_uint64_t *recipient_userid)
1574 {
1575 DB_RESULT result;
1576 DB_ROW row;
1577 char *buf = NULL, *p;
1578 size_t buf_alloc = ZBX_KIBIBYTE, buf_offset = 0;
1579 int esc_step;
1580 unsigned char type, status;
1581 time_t now;
1582 zbx_uint64_t userid;
1583
1584 buf = (char *)zbx_malloc(buf, buf_alloc);
1585
1586 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Problem started: %s %s Age: %s\n",
1587 zbx_date2str(event->clock), zbx_time2str(event->clock),
1588 zbx_age2str(time(NULL) - event->clock));
1589
1590 result = DBselect("select a.clock,a.alerttype,a.status,mt.description,a.sendto"
1591 ",a.error,a.esc_step,a.userid,a.message"
1592 " from alerts a"
1593 " left join media_type mt"
1594 " on mt.mediatypeid=a.mediatypeid"
1595 " where a.eventid=" ZBX_FS_UI64
1596 " and a.actionid=" ZBX_FS_UI64
1597 " order by a.clock",
1598 event->eventid, actionid);
1599
1600 while (NULL != (row = DBfetch(result)))
1601 {
1602 int user_permit;
1603
1604 now = atoi(row[0]);
1605 type = (unsigned char)atoi(row[1]);
1606 status = (unsigned char)atoi(row[2]);
1607 esc_step = atoi(row[6]);
1608 ZBX_DBROW2UINT64(userid, row[7]);
1609 user_permit = zbx_check_user_permissions(&userid, recipient_userid);
1610
1611 if (0 != esc_step)
1612 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%d. ", esc_step);
1613
1614 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%s %s %-7s %-11s",
1615 zbx_date2str(now), zbx_time2str(now), /* date, time */
1616 zbx_alert_type_string(type), /* alert type */
1617 zbx_alert_status_string(type, status)); /* alert status */
1618
1619 if (ALERT_TYPE_COMMAND == type)
1620 {
1621 if (NULL != (p = strchr(row[8], ':')))
1622 {
1623 *p = '\0';
1624 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " \"%s\"", row[8]); /* host */
1625 *p = ':';
1626 }
1627 }
1628 else
1629 {
1630 const char *description, *send_to, *user_name;
1631
1632 description = (SUCCEED == DBis_null(row[3]) ? "" : row[3]);
1633
1634 if (SUCCEED == user_permit)
1635 {
1636 send_to = row[4];
1637 user_name = zbx_user_string(userid);
1638 }
1639 else
1640 {
1641 send_to = "\"Inaccessible recipient details\"";
1642 user_name = "Inaccessible user";
1643 }
1644
1645 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s %s \"%s\"",
1646 description, /* media type description */
1647 send_to, /* historical recipient */
1648 user_name); /* alert user full name */
1649 }
1650
1651 if (ALERT_STATUS_FAILED == status)
1652 {
1653 /* alert error can be generated by SMTP Relay or other media and contain sensitive details */
1654 if (SUCCEED == user_permit)
1655 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s", row[5]);
1656 else
1657 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, " \"Inaccessible error message\"");
1658 }
1659
1660 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, '\n');
1661 }
1662 DBfree_result(result);
1663
1664 if (NULL != r_event)
1665 {
1666 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Problem ended: %s %s\n",
1667 zbx_date2str(r_event->clock), zbx_time2str(r_event->clock));
1668 }
1669
1670 if (0 != buf_offset)
1671 buf[--buf_offset] = '\0';
1672
1673 *replace_to = buf;
1674 }
1675
1676 /******************************************************************************
1677 * *
1678 * Function: get_event_update_history *
1679 * *
1680 * Purpose: retrieve event acknowledges history *
1681 * *
1682 * Parameters: *
1683 * *
1684 * Author: Alexander Vladishev *
1685 * *
1686 * Comments: *
1687 * *
1688 ******************************************************************************/
get_event_update_history(const DB_EVENT * event,char ** replace_to,const zbx_uint64_t * recipient_userid)1689 static void get_event_update_history(const DB_EVENT *event, char **replace_to, const zbx_uint64_t *recipient_userid)
1690 {
1691 DB_RESULT result;
1692 DB_ROW row;
1693 char *buf = NULL;
1694 size_t buf_alloc = ZBX_KIBIBYTE, buf_offset = 0;
1695
1696 buf = (char *)zbx_malloc(buf, buf_alloc);
1697 *buf = '\0';
1698
1699 result = DBselect("select clock,userid,message,action,old_severity,new_severity"
1700 " from acknowledges"
1701 " where eventid=" ZBX_FS_UI64 " order by clock",
1702 event->eventid);
1703
1704 while (NULL != (row = DBfetch(result)))
1705 {
1706 const char *user_name;
1707 char *actions = NULL;
1708 DB_ACKNOWLEDGE ack;
1709
1710 ack.clock = atoi(row[0]);
1711 ZBX_STR2UINT64(ack.userid, row[1]);
1712 ack.message = row[2];
1713 ack.acknowledgeid = 0;
1714 ack.action = atoi(row[3]);
1715 ack.old_severity = atoi(row[4]);
1716 ack.new_severity = atoi(row[5]);
1717
1718 if (SUCCEED == zbx_check_user_permissions(&ack.userid, recipient_userid))
1719 user_name = zbx_user_string(ack.userid);
1720 else
1721 user_name = "Inaccessible user";
1722
1723 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
1724 "%s %s \"%s\"\n",
1725 zbx_date2str(ack.clock),
1726 zbx_time2str(ack.clock),
1727 user_name);
1728
1729 if (SUCCEED == get_problem_update_actions(&ack, ZBX_PROBLEM_UPDATE_ACKNOWLEDGE |
1730 ZBX_PROBLEM_UPDATE_CLOSE | ZBX_PROBLEM_UPDATE_SEVERITY, &actions))
1731 {
1732 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Actions: %s.\n", actions);
1733 zbx_free(actions);
1734 }
1735
1736 if ('\0' != *ack.message)
1737 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%s\n", ack.message);
1738
1739 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, '\n');
1740 }
1741 DBfree_result(result);
1742
1743 if (0 != buf_offset)
1744 {
1745 buf_offset -= 2;
1746 buf[buf_offset] = '\0';
1747 }
1748
1749 *replace_to = buf;
1750 }
1751
1752 /******************************************************************************
1753 * *
1754 * Function: get_autoreg_value_by_event *
1755 * *
1756 * Purpose: request value from autoreg_host table by event *
1757 * *
1758 * Parameters: *
1759 * *
1760 * Return value: upon successful completion return SUCCEED *
1761 * otherwise FAIL *
1762 * *
1763 * Author: Alexander Vladishev *
1764 * *
1765 * Comments: *
1766 * *
1767 ******************************************************************************/
get_autoreg_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1768 static int get_autoreg_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1769 {
1770 DB_RESULT result;
1771 DB_ROW row;
1772 int ret = FAIL;
1773
1774 result = DBselect(
1775 "select %s"
1776 " from autoreg_host"
1777 " where autoreg_hostid=" ZBX_FS_UI64, fieldname, event->objectid);
1778
1779 if (NULL != (row = DBfetch(result)))
1780 {
1781 *replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1782 ret = SUCCEED;
1783 }
1784 DBfree_result(result);
1785
1786 return ret;
1787 }
1788
1789 #define MVAR_ACTION "{ACTION." /* a prefix for all action macros */
1790 #define MVAR_ACTION_ID MVAR_ACTION "ID}"
1791 #define MVAR_ACTION_NAME MVAR_ACTION "NAME}"
1792 #define MVAR_DATE "{DATE}"
1793 #define MVAR_EVENT "{EVENT." /* a prefix for all event macros */
1794 #define MVAR_EVENT_ACK_HISTORY MVAR_EVENT "ACK.HISTORY}" /* deprecated */
1795 #define MVAR_EVENT_ACK_STATUS MVAR_EVENT "ACK.STATUS}"
1796 #define MVAR_EVENT_AGE MVAR_EVENT "AGE}"
1797 #define MVAR_EVENT_DATE MVAR_EVENT "DATE}"
1798 #define MVAR_EVENT_ID MVAR_EVENT "ID}"
1799 #define MVAR_EVENT_NAME MVAR_EVENT "NAME}"
1800 #define MVAR_EVENT_STATUS MVAR_EVENT "STATUS}"
1801 #define MVAR_EVENT_TAGS MVAR_EVENT "TAGS}"
1802 #define MVAR_EVENT_TIME MVAR_EVENT "TIME}"
1803 #define MVAR_EVENT_VALUE MVAR_EVENT "VALUE}"
1804 #define MVAR_EVENT_SEVERITY MVAR_EVENT "SEVERITY}"
1805 #define MVAR_EVENT_NSEVERITY MVAR_EVENT "NSEVERITY}"
1806 #define MVAR_EVENT_RECOVERY MVAR_EVENT "RECOVERY." /* a prefix for all recovery event macros */
1807 #define MVAR_EVENT_RECOVERY_DATE MVAR_EVENT_RECOVERY "DATE}"
1808 #define MVAR_EVENT_RECOVERY_ID MVAR_EVENT_RECOVERY "ID}"
1809 #define MVAR_EVENT_RECOVERY_STATUS MVAR_EVENT_RECOVERY "STATUS}" /* deprecated */
1810 #define MVAR_EVENT_RECOVERY_TAGS MVAR_EVENT_RECOVERY "TAGS}"
1811 #define MVAR_EVENT_RECOVERY_TIME MVAR_EVENT_RECOVERY "TIME}"
1812 #define MVAR_EVENT_RECOVERY_VALUE MVAR_EVENT_RECOVERY "VALUE}" /* deprecated */
1813 #define MVAR_EVENT_RECOVERY_NAME MVAR_EVENT_RECOVERY "NAME}"
1814 #define MVAR_EVENT_UPDATE MVAR_EVENT "UPDATE."
1815 #define MVAR_EVENT_UPDATE_ACTION MVAR_EVENT_UPDATE "ACTION}"
1816 #define MVAR_EVENT_UPDATE_DATE MVAR_EVENT_UPDATE "DATE}"
1817 #define MVAR_EVENT_UPDATE_HISTORY MVAR_EVENT_UPDATE "HISTORY}"
1818 #define MVAR_EVENT_UPDATE_MESSAGE MVAR_EVENT_UPDATE "MESSAGE}"
1819 #define MVAR_EVENT_UPDATE_TIME MVAR_EVENT_UPDATE "TIME}"
1820
1821 #define MVAR_ESC_HISTORY "{ESC.HISTORY}"
1822 #define MVAR_PROXY_NAME "{PROXY.NAME}"
1823 #define MVAR_PROXY_DESCRIPTION "{PROXY.DESCRIPTION}"
1824 #define MVAR_HOST_DNS "{HOST.DNS}"
1825 #define MVAR_HOST_CONN "{HOST.CONN}"
1826 #define MVAR_HOST_HOST "{HOST.HOST}"
1827 #define MVAR_HOST_ID "{HOST.ID}"
1828 #define MVAR_HOST_IP "{HOST.IP}"
1829 #define MVAR_IPADDRESS "{IPADDRESS}" /* deprecated */
1830 #define MVAR_HOST_METADATA "{HOST.METADATA}"
1831 #define MVAR_HOST_NAME "{HOST.NAME}"
1832 #define MVAR_HOSTNAME "{HOSTNAME}" /* deprecated */
1833 #define MVAR_HOST_DESCRIPTION "{HOST.DESCRIPTION}"
1834 #define MVAR_HOST_PORT "{HOST.PORT}"
1835 #define MVAR_TIME "{TIME}"
1836 #define MVAR_ITEM_LASTVALUE "{ITEM.LASTVALUE}"
1837 #define MVAR_ITEM_VALUE "{ITEM.VALUE}"
1838 #define MVAR_ITEM_ID "{ITEM.ID}"
1839 #define MVAR_ITEM_NAME "{ITEM.NAME}"
1840 #define MVAR_ITEM_NAME_ORIG "{ITEM.NAME.ORIG}"
1841 #define MVAR_ITEM_KEY "{ITEM.KEY}"
1842 #define MVAR_ITEM_KEY_ORIG "{ITEM.KEY.ORIG}"
1843 #define MVAR_ITEM_STATE "{ITEM.STATE}"
1844 #define MVAR_TRIGGER_KEY "{TRIGGER.KEY}" /* deprecated */
1845 #define MVAR_ITEM_DESCRIPTION "{ITEM.DESCRIPTION}"
1846 #define MVAR_ITEM_LOG_DATE "{ITEM.LOG.DATE}"
1847 #define MVAR_ITEM_LOG_TIME "{ITEM.LOG.TIME}"
1848 #define MVAR_ITEM_LOG_AGE "{ITEM.LOG.AGE}"
1849 #define MVAR_ITEM_LOG_SOURCE "{ITEM.LOG.SOURCE}"
1850 #define MVAR_ITEM_LOG_SEVERITY "{ITEM.LOG.SEVERITY}"
1851 #define MVAR_ITEM_LOG_NSEVERITY "{ITEM.LOG.NSEVERITY}"
1852 #define MVAR_ITEM_LOG_EVENTID "{ITEM.LOG.EVENTID}"
1853
1854 #define MVAR_TRIGGER_DESCRIPTION "{TRIGGER.DESCRIPTION}"
1855 #define MVAR_TRIGGER_COMMENT "{TRIGGER.COMMENT}" /* deprecated */
1856 #define MVAR_TRIGGER_ID "{TRIGGER.ID}"
1857 #define MVAR_TRIGGER_NAME "{TRIGGER.NAME}"
1858 #define MVAR_TRIGGER_NAME_ORIG "{TRIGGER.NAME.ORIG}"
1859 #define MVAR_TRIGGER_EXPRESSION "{TRIGGER.EXPRESSION}"
1860 #define MVAR_TRIGGER_EXPRESSION_RECOVERY "{TRIGGER.EXPRESSION.RECOVERY}"
1861 #define MVAR_TRIGGER_SEVERITY "{TRIGGER.SEVERITY}"
1862 #define MVAR_TRIGGER_NSEVERITY "{TRIGGER.NSEVERITY}"
1863 #define MVAR_TRIGGER_STATUS "{TRIGGER.STATUS}"
1864 #define MVAR_TRIGGER_STATE "{TRIGGER.STATE}"
1865 #define MVAR_TRIGGER_TEMPLATE_NAME "{TRIGGER.TEMPLATE.NAME}"
1866 #define MVAR_TRIGGER_HOSTGROUP_NAME "{TRIGGER.HOSTGROUP.NAME}"
1867 #define MVAR_STATUS "{STATUS}" /* deprecated */
1868 #define MVAR_TRIGGER_VALUE "{TRIGGER.VALUE}"
1869 #define MVAR_TRIGGER_URL "{TRIGGER.URL}"
1870
1871 #define MVAR_TRIGGER_EVENTS_ACK "{TRIGGER.EVENTS.ACK}"
1872 #define MVAR_TRIGGER_EVENTS_UNACK "{TRIGGER.EVENTS.UNACK}"
1873 #define MVAR_TRIGGER_EVENTS_PROBLEM_ACK "{TRIGGER.EVENTS.PROBLEM.ACK}"
1874 #define MVAR_TRIGGER_EVENTS_PROBLEM_UNACK "{TRIGGER.EVENTS.PROBLEM.UNACK}"
1875
1876 #define MVAR_LLDRULE_DESCRIPTION "{LLDRULE.DESCRIPTION}"
1877 #define MVAR_LLDRULE_ID "{LLDRULE.ID}"
1878 #define MVAR_LLDRULE_KEY "{LLDRULE.KEY}"
1879 #define MVAR_LLDRULE_KEY_ORIG "{LLDRULE.KEY.ORIG}"
1880 #define MVAR_LLDRULE_NAME "{LLDRULE.NAME}"
1881 #define MVAR_LLDRULE_NAME_ORIG "{LLDRULE.NAME.ORIG}"
1882 #define MVAR_LLDRULE_STATE "{LLDRULE.STATE}"
1883
1884 #define MVAR_INVENTORY "{INVENTORY." /* a prefix for all inventory macros */
1885 #define MVAR_INVENTORY_TYPE MVAR_INVENTORY "TYPE}"
1886 #define MVAR_INVENTORY_TYPE_FULL MVAR_INVENTORY "TYPE.FULL}"
1887 #define MVAR_INVENTORY_NAME MVAR_INVENTORY "NAME}"
1888 #define MVAR_INVENTORY_ALIAS MVAR_INVENTORY "ALIAS}"
1889 #define MVAR_INVENTORY_OS MVAR_INVENTORY "OS}"
1890 #define MVAR_INVENTORY_OS_FULL MVAR_INVENTORY "OS.FULL}"
1891 #define MVAR_INVENTORY_OS_SHORT MVAR_INVENTORY "OS.SHORT}"
1892 #define MVAR_INVENTORY_SERIALNO_A MVAR_INVENTORY "SERIALNO.A}"
1893 #define MVAR_INVENTORY_SERIALNO_B MVAR_INVENTORY "SERIALNO.B}"
1894 #define MVAR_INVENTORY_TAG MVAR_INVENTORY "TAG}"
1895 #define MVAR_INVENTORY_ASSET_TAG MVAR_INVENTORY "ASSET.TAG}"
1896 #define MVAR_INVENTORY_MACADDRESS_A MVAR_INVENTORY "MACADDRESS.A}"
1897 #define MVAR_INVENTORY_MACADDRESS_B MVAR_INVENTORY "MACADDRESS.B}"
1898 #define MVAR_INVENTORY_HARDWARE MVAR_INVENTORY "HARDWARE}"
1899 #define MVAR_INVENTORY_HARDWARE_FULL MVAR_INVENTORY "HARDWARE.FULL}"
1900 #define MVAR_INVENTORY_SOFTWARE MVAR_INVENTORY "SOFTWARE}"
1901 #define MVAR_INVENTORY_SOFTWARE_FULL MVAR_INVENTORY "SOFTWARE.FULL}"
1902 #define MVAR_INVENTORY_SOFTWARE_APP_A MVAR_INVENTORY "SOFTWARE.APP.A}"
1903 #define MVAR_INVENTORY_SOFTWARE_APP_B MVAR_INVENTORY "SOFTWARE.APP.B}"
1904 #define MVAR_INVENTORY_SOFTWARE_APP_C MVAR_INVENTORY "SOFTWARE.APP.C}"
1905 #define MVAR_INVENTORY_SOFTWARE_APP_D MVAR_INVENTORY "SOFTWARE.APP.D}"
1906 #define MVAR_INVENTORY_SOFTWARE_APP_E MVAR_INVENTORY "SOFTWARE.APP.E}"
1907 #define MVAR_INVENTORY_CONTACT MVAR_INVENTORY "CONTACT}"
1908 #define MVAR_INVENTORY_LOCATION MVAR_INVENTORY "LOCATION}"
1909 #define MVAR_INVENTORY_LOCATION_LAT MVAR_INVENTORY "LOCATION.LAT}"
1910 #define MVAR_INVENTORY_LOCATION_LON MVAR_INVENTORY "LOCATION.LON}"
1911 #define MVAR_INVENTORY_NOTES MVAR_INVENTORY "NOTES}"
1912 #define MVAR_INVENTORY_CHASSIS MVAR_INVENTORY "CHASSIS}"
1913 #define MVAR_INVENTORY_MODEL MVAR_INVENTORY "MODEL}"
1914 #define MVAR_INVENTORY_HW_ARCH MVAR_INVENTORY "HW.ARCH}"
1915 #define MVAR_INVENTORY_VENDOR MVAR_INVENTORY "VENDOR}"
1916 #define MVAR_INVENTORY_CONTRACT_NUMBER MVAR_INVENTORY "CONTRACT.NUMBER}"
1917 #define MVAR_INVENTORY_INSTALLER_NAME MVAR_INVENTORY "INSTALLER.NAME}"
1918 #define MVAR_INVENTORY_DEPLOYMENT_STATUS MVAR_INVENTORY "DEPLOYMENT.STATUS}"
1919 #define MVAR_INVENTORY_URL_A MVAR_INVENTORY "URL.A}"
1920 #define MVAR_INVENTORY_URL_B MVAR_INVENTORY "URL.B}"
1921 #define MVAR_INVENTORY_URL_C MVAR_INVENTORY "URL.C}"
1922 #define MVAR_INVENTORY_HOST_NETWORKS MVAR_INVENTORY "HOST.NETWORKS}"
1923 #define MVAR_INVENTORY_HOST_NETMASK MVAR_INVENTORY "HOST.NETMASK}"
1924 #define MVAR_INVENTORY_HOST_ROUTER MVAR_INVENTORY "HOST.ROUTER}"
1925 #define MVAR_INVENTORY_OOB_IP MVAR_INVENTORY "OOB.IP}"
1926 #define MVAR_INVENTORY_OOB_NETMASK MVAR_INVENTORY "OOB.NETMASK}"
1927 #define MVAR_INVENTORY_OOB_ROUTER MVAR_INVENTORY "OOB.ROUTER}"
1928 #define MVAR_INVENTORY_HW_DATE_PURCHASE MVAR_INVENTORY "HW.DATE.PURCHASE}"
1929 #define MVAR_INVENTORY_HW_DATE_INSTALL MVAR_INVENTORY "HW.DATE.INSTALL}"
1930 #define MVAR_INVENTORY_HW_DATE_EXPIRY MVAR_INVENTORY "HW.DATE.EXPIRY}"
1931 #define MVAR_INVENTORY_HW_DATE_DECOMM MVAR_INVENTORY "HW.DATE.DECOMM}"
1932 #define MVAR_INVENTORY_SITE_ADDRESS_A MVAR_INVENTORY "SITE.ADDRESS.A}"
1933 #define MVAR_INVENTORY_SITE_ADDRESS_B MVAR_INVENTORY "SITE.ADDRESS.B}"
1934 #define MVAR_INVENTORY_SITE_ADDRESS_C MVAR_INVENTORY "SITE.ADDRESS.C}"
1935 #define MVAR_INVENTORY_SITE_CITY MVAR_INVENTORY "SITE.CITY}"
1936 #define MVAR_INVENTORY_SITE_STATE MVAR_INVENTORY "SITE.STATE}"
1937 #define MVAR_INVENTORY_SITE_COUNTRY MVAR_INVENTORY "SITE.COUNTRY}"
1938 #define MVAR_INVENTORY_SITE_ZIP MVAR_INVENTORY "SITE.ZIP}"
1939 #define MVAR_INVENTORY_SITE_RACK MVAR_INVENTORY "SITE.RACK}"
1940 #define MVAR_INVENTORY_SITE_NOTES MVAR_INVENTORY "SITE.NOTES}"
1941 #define MVAR_INVENTORY_POC_PRIMARY_NAME MVAR_INVENTORY "POC.PRIMARY.NAME}"
1942 #define MVAR_INVENTORY_POC_PRIMARY_EMAIL MVAR_INVENTORY "POC.PRIMARY.EMAIL}"
1943 #define MVAR_INVENTORY_POC_PRIMARY_PHONE_A MVAR_INVENTORY "POC.PRIMARY.PHONE.A}"
1944 #define MVAR_INVENTORY_POC_PRIMARY_PHONE_B MVAR_INVENTORY "POC.PRIMARY.PHONE.B}"
1945 #define MVAR_INVENTORY_POC_PRIMARY_CELL MVAR_INVENTORY "POC.PRIMARY.CELL}"
1946 #define MVAR_INVENTORY_POC_PRIMARY_SCREEN MVAR_INVENTORY "POC.PRIMARY.SCREEN}"
1947 #define MVAR_INVENTORY_POC_PRIMARY_NOTES MVAR_INVENTORY "POC.PRIMARY.NOTES}"
1948 #define MVAR_INVENTORY_POC_SECONDARY_NAME MVAR_INVENTORY "POC.SECONDARY.NAME}"
1949 #define MVAR_INVENTORY_POC_SECONDARY_EMAIL MVAR_INVENTORY "POC.SECONDARY.EMAIL}"
1950 #define MVAR_INVENTORY_POC_SECONDARY_PHONE_A MVAR_INVENTORY "POC.SECONDARY.PHONE.A}"
1951 #define MVAR_INVENTORY_POC_SECONDARY_PHONE_B MVAR_INVENTORY "POC.SECONDARY.PHONE.B}"
1952 #define MVAR_INVENTORY_POC_SECONDARY_CELL MVAR_INVENTORY "POC.SECONDARY.CELL}"
1953 #define MVAR_INVENTORY_POC_SECONDARY_SCREEN MVAR_INVENTORY "POC.SECONDARY.SCREEN}"
1954 #define MVAR_INVENTORY_POC_SECONDARY_NOTES MVAR_INVENTORY "POC.SECONDARY.NOTES}"
1955
1956 /* PROFILE.* is deprecated, use INVENTORY.* instead */
1957 #define MVAR_PROFILE "{PROFILE." /* prefix for profile macros */
1958 #define MVAR_PROFILE_DEVICETYPE MVAR_PROFILE "DEVICETYPE}"
1959 #define MVAR_PROFILE_NAME MVAR_PROFILE "NAME}"
1960 #define MVAR_PROFILE_OS MVAR_PROFILE "OS}"
1961 #define MVAR_PROFILE_SERIALNO MVAR_PROFILE "SERIALNO}"
1962 #define MVAR_PROFILE_TAG MVAR_PROFILE "TAG}"
1963 #define MVAR_PROFILE_MACADDRESS MVAR_PROFILE "MACADDRESS}"
1964 #define MVAR_PROFILE_HARDWARE MVAR_PROFILE "HARDWARE}"
1965 #define MVAR_PROFILE_SOFTWARE MVAR_PROFILE "SOFTWARE}"
1966 #define MVAR_PROFILE_CONTACT MVAR_PROFILE "CONTACT}"
1967 #define MVAR_PROFILE_LOCATION MVAR_PROFILE "LOCATION}"
1968 #define MVAR_PROFILE_NOTES MVAR_PROFILE "NOTES}"
1969
1970 #define MVAR_DISCOVERY_RULE_NAME "{DISCOVERY.RULE.NAME}"
1971 #define MVAR_DISCOVERY_SERVICE_NAME "{DISCOVERY.SERVICE.NAME}"
1972 #define MVAR_DISCOVERY_SERVICE_PORT "{DISCOVERY.SERVICE.PORT}"
1973 #define MVAR_DISCOVERY_SERVICE_STATUS "{DISCOVERY.SERVICE.STATUS}"
1974 #define MVAR_DISCOVERY_SERVICE_UPTIME "{DISCOVERY.SERVICE.UPTIME}"
1975 #define MVAR_DISCOVERY_DEVICE_IPADDRESS "{DISCOVERY.DEVICE.IPADDRESS}"
1976 #define MVAR_DISCOVERY_DEVICE_DNS "{DISCOVERY.DEVICE.DNS}"
1977 #define MVAR_DISCOVERY_DEVICE_STATUS "{DISCOVERY.DEVICE.STATUS}"
1978 #define MVAR_DISCOVERY_DEVICE_UPTIME "{DISCOVERY.DEVICE.UPTIME}"
1979
1980 #define MVAR_ALERT_SENDTO "{ALERT.SENDTO}"
1981 #define MVAR_ALERT_SUBJECT "{ALERT.SUBJECT}"
1982 #define MVAR_ALERT_MESSAGE "{ALERT.MESSAGE}"
1983
1984 #define MVAR_ACK_MESSAGE "{ACK.MESSAGE}" /* deprecated */
1985 #define MVAR_ACK_TIME "{ACK.TIME}" /* deprecated */
1986 #define MVAR_ACK_DATE "{ACK.DATE}" /* deprecated */
1987 #define MVAR_USER_FULLNAME "{USER.FULLNAME}"
1988
1989 #define STR_UNKNOWN_VARIABLE "*UNKNOWN*"
1990
1991 /* macros that can be indexed */
1992 static const char *ex_macros[] =
1993 {
1994 MVAR_INVENTORY_TYPE, MVAR_INVENTORY_TYPE_FULL,
1995 MVAR_INVENTORY_NAME, MVAR_INVENTORY_ALIAS, MVAR_INVENTORY_OS, MVAR_INVENTORY_OS_FULL, MVAR_INVENTORY_OS_SHORT,
1996 MVAR_INVENTORY_SERIALNO_A, MVAR_INVENTORY_SERIALNO_B, MVAR_INVENTORY_TAG,
1997 MVAR_INVENTORY_ASSET_TAG, MVAR_INVENTORY_MACADDRESS_A, MVAR_INVENTORY_MACADDRESS_B,
1998 MVAR_INVENTORY_HARDWARE, MVAR_INVENTORY_HARDWARE_FULL, MVAR_INVENTORY_SOFTWARE, MVAR_INVENTORY_SOFTWARE_FULL,
1999 MVAR_INVENTORY_SOFTWARE_APP_A, MVAR_INVENTORY_SOFTWARE_APP_B, MVAR_INVENTORY_SOFTWARE_APP_C,
2000 MVAR_INVENTORY_SOFTWARE_APP_D, MVAR_INVENTORY_SOFTWARE_APP_E, MVAR_INVENTORY_CONTACT, MVAR_INVENTORY_LOCATION,
2001 MVAR_INVENTORY_LOCATION_LAT, MVAR_INVENTORY_LOCATION_LON, MVAR_INVENTORY_NOTES, MVAR_INVENTORY_CHASSIS,
2002 MVAR_INVENTORY_MODEL, MVAR_INVENTORY_HW_ARCH, MVAR_INVENTORY_VENDOR, MVAR_INVENTORY_CONTRACT_NUMBER,
2003 MVAR_INVENTORY_INSTALLER_NAME, MVAR_INVENTORY_DEPLOYMENT_STATUS, MVAR_INVENTORY_URL_A, MVAR_INVENTORY_URL_B,
2004 MVAR_INVENTORY_URL_C, MVAR_INVENTORY_HOST_NETWORKS, MVAR_INVENTORY_HOST_NETMASK, MVAR_INVENTORY_HOST_ROUTER,
2005 MVAR_INVENTORY_OOB_IP, MVAR_INVENTORY_OOB_NETMASK, MVAR_INVENTORY_OOB_ROUTER, MVAR_INVENTORY_HW_DATE_PURCHASE,
2006 MVAR_INVENTORY_HW_DATE_INSTALL, MVAR_INVENTORY_HW_DATE_EXPIRY, MVAR_INVENTORY_HW_DATE_DECOMM,
2007 MVAR_INVENTORY_SITE_ADDRESS_A, MVAR_INVENTORY_SITE_ADDRESS_B, MVAR_INVENTORY_SITE_ADDRESS_C,
2008 MVAR_INVENTORY_SITE_CITY, MVAR_INVENTORY_SITE_STATE, MVAR_INVENTORY_SITE_COUNTRY, MVAR_INVENTORY_SITE_ZIP,
2009 MVAR_INVENTORY_SITE_RACK, MVAR_INVENTORY_SITE_NOTES, MVAR_INVENTORY_POC_PRIMARY_NAME,
2010 MVAR_INVENTORY_POC_PRIMARY_EMAIL, MVAR_INVENTORY_POC_PRIMARY_PHONE_A, MVAR_INVENTORY_POC_PRIMARY_PHONE_B,
2011 MVAR_INVENTORY_POC_PRIMARY_CELL, MVAR_INVENTORY_POC_PRIMARY_SCREEN, MVAR_INVENTORY_POC_PRIMARY_NOTES,
2012 MVAR_INVENTORY_POC_SECONDARY_NAME, MVAR_INVENTORY_POC_SECONDARY_EMAIL, MVAR_INVENTORY_POC_SECONDARY_PHONE_A,
2013 MVAR_INVENTORY_POC_SECONDARY_PHONE_B, MVAR_INVENTORY_POC_SECONDARY_CELL, MVAR_INVENTORY_POC_SECONDARY_SCREEN,
2014 MVAR_INVENTORY_POC_SECONDARY_NOTES,
2015 /* PROFILE.* is deprecated, use INVENTORY.* instead */
2016 MVAR_PROFILE_DEVICETYPE, MVAR_PROFILE_NAME, MVAR_PROFILE_OS, MVAR_PROFILE_SERIALNO,
2017 MVAR_PROFILE_TAG, MVAR_PROFILE_MACADDRESS, MVAR_PROFILE_HARDWARE, MVAR_PROFILE_SOFTWARE,
2018 MVAR_PROFILE_CONTACT, MVAR_PROFILE_LOCATION, MVAR_PROFILE_NOTES,
2019 MVAR_HOST_HOST, MVAR_HOSTNAME, MVAR_HOST_NAME, MVAR_HOST_DESCRIPTION, MVAR_PROXY_NAME, MVAR_PROXY_DESCRIPTION,
2020 MVAR_HOST_CONN, MVAR_HOST_DNS, MVAR_HOST_IP, MVAR_HOST_PORT, MVAR_IPADDRESS, MVAR_HOST_ID,
2021 MVAR_ITEM_ID, MVAR_ITEM_NAME, MVAR_ITEM_NAME_ORIG, MVAR_ITEM_DESCRIPTION,
2022 MVAR_ITEM_KEY, MVAR_ITEM_KEY_ORIG, MVAR_TRIGGER_KEY,
2023 MVAR_ITEM_LASTVALUE,
2024 MVAR_ITEM_STATE,
2025 MVAR_ITEM_VALUE,
2026 MVAR_ITEM_LOG_DATE, MVAR_ITEM_LOG_TIME, MVAR_ITEM_LOG_AGE, MVAR_ITEM_LOG_SOURCE,
2027 MVAR_ITEM_LOG_SEVERITY, MVAR_ITEM_LOG_NSEVERITY, MVAR_ITEM_LOG_EVENTID,
2028 NULL
2029 };
2030
2031 /* macros that are supported as simple macro host and item key */
2032 static const char *simple_host_macros[] = {MVAR_HOST_HOST, MVAR_HOSTNAME, NULL};
2033 static const char *simple_key_macros[] = {MVAR_ITEM_KEY, MVAR_TRIGGER_KEY, NULL};
2034
2035 /* macros that can be modified using macro functions */
2036 static const char *mod_macros[] = {MVAR_ITEM_VALUE, MVAR_ITEM_LASTVALUE, NULL};
2037
2038 typedef struct
2039 {
2040 const char *macro;
2041 int idx;
2042 } inventory_field_t;
2043
2044 static inventory_field_t inventory_fields[] =
2045 {
2046 {MVAR_INVENTORY_TYPE, 0},
2047 {MVAR_PROFILE_DEVICETYPE, 0}, /* deprecated */
2048 {MVAR_INVENTORY_TYPE_FULL, 1},
2049 {MVAR_INVENTORY_NAME, 2},
2050 {MVAR_PROFILE_NAME, 2}, /* deprecated */
2051 {MVAR_INVENTORY_ALIAS, 3},
2052 {MVAR_INVENTORY_OS, 4},
2053 {MVAR_PROFILE_OS, 4}, /* deprecated */
2054 {MVAR_INVENTORY_OS_FULL, 5},
2055 {MVAR_INVENTORY_OS_SHORT, 6},
2056 {MVAR_INVENTORY_SERIALNO_A, 7},
2057 {MVAR_PROFILE_SERIALNO, 7}, /* deprecated */
2058 {MVAR_INVENTORY_SERIALNO_B, 8},
2059 {MVAR_INVENTORY_TAG, 9},
2060 {MVAR_PROFILE_TAG, 9}, /* deprecated */
2061 {MVAR_INVENTORY_ASSET_TAG, 10},
2062 {MVAR_INVENTORY_MACADDRESS_A, 11},
2063 {MVAR_PROFILE_MACADDRESS, 11}, /* deprecated */
2064 {MVAR_INVENTORY_MACADDRESS_B, 12},
2065 {MVAR_INVENTORY_HARDWARE, 13},
2066 {MVAR_PROFILE_HARDWARE, 13}, /* deprecated */
2067 {MVAR_INVENTORY_HARDWARE_FULL, 14},
2068 {MVAR_INVENTORY_SOFTWARE, 15},
2069 {MVAR_PROFILE_SOFTWARE, 15}, /* deprecated */
2070 {MVAR_INVENTORY_SOFTWARE_FULL, 16},
2071 {MVAR_INVENTORY_SOFTWARE_APP_A, 17},
2072 {MVAR_INVENTORY_SOFTWARE_APP_B, 18},
2073 {MVAR_INVENTORY_SOFTWARE_APP_C, 19},
2074 {MVAR_INVENTORY_SOFTWARE_APP_D, 20},
2075 {MVAR_INVENTORY_SOFTWARE_APP_E, 21},
2076 {MVAR_INVENTORY_CONTACT, 22},
2077 {MVAR_PROFILE_CONTACT, 22}, /* deprecated */
2078 {MVAR_INVENTORY_LOCATION, 23},
2079 {MVAR_PROFILE_LOCATION, 23}, /* deprecated */
2080 {MVAR_INVENTORY_LOCATION_LAT, 24},
2081 {MVAR_INVENTORY_LOCATION_LON, 25},
2082 {MVAR_INVENTORY_NOTES, 26},
2083 {MVAR_PROFILE_NOTES, 26}, /* deprecated */
2084 {MVAR_INVENTORY_CHASSIS, 27},
2085 {MVAR_INVENTORY_MODEL, 28},
2086 {MVAR_INVENTORY_HW_ARCH, 29},
2087 {MVAR_INVENTORY_VENDOR, 30},
2088 {MVAR_INVENTORY_CONTRACT_NUMBER, 31},
2089 {MVAR_INVENTORY_INSTALLER_NAME, 32},
2090 {MVAR_INVENTORY_DEPLOYMENT_STATUS, 33},
2091 {MVAR_INVENTORY_URL_A, 34},
2092 {MVAR_INVENTORY_URL_B, 35},
2093 {MVAR_INVENTORY_URL_C, 36},
2094 {MVAR_INVENTORY_HOST_NETWORKS, 37},
2095 {MVAR_INVENTORY_HOST_NETMASK, 38},
2096 {MVAR_INVENTORY_HOST_ROUTER, 39},
2097 {MVAR_INVENTORY_OOB_IP, 40},
2098 {MVAR_INVENTORY_OOB_NETMASK, 41},
2099 {MVAR_INVENTORY_OOB_ROUTER, 42},
2100 {MVAR_INVENTORY_HW_DATE_PURCHASE, 43},
2101 {MVAR_INVENTORY_HW_DATE_INSTALL, 44},
2102 {MVAR_INVENTORY_HW_DATE_EXPIRY, 45},
2103 {MVAR_INVENTORY_HW_DATE_DECOMM, 46},
2104 {MVAR_INVENTORY_SITE_ADDRESS_A, 47},
2105 {MVAR_INVENTORY_SITE_ADDRESS_B, 48},
2106 {MVAR_INVENTORY_SITE_ADDRESS_C, 49},
2107 {MVAR_INVENTORY_SITE_CITY, 50},
2108 {MVAR_INVENTORY_SITE_STATE, 51},
2109 {MVAR_INVENTORY_SITE_COUNTRY, 52},
2110 {MVAR_INVENTORY_SITE_ZIP, 53},
2111 {MVAR_INVENTORY_SITE_RACK, 54},
2112 {MVAR_INVENTORY_SITE_NOTES, 55},
2113 {MVAR_INVENTORY_POC_PRIMARY_NAME, 56},
2114 {MVAR_INVENTORY_POC_PRIMARY_EMAIL, 57},
2115 {MVAR_INVENTORY_POC_PRIMARY_PHONE_A, 58},
2116 {MVAR_INVENTORY_POC_PRIMARY_PHONE_B, 59},
2117 {MVAR_INVENTORY_POC_PRIMARY_CELL, 60},
2118 {MVAR_INVENTORY_POC_PRIMARY_SCREEN, 61},
2119 {MVAR_INVENTORY_POC_PRIMARY_NOTES, 62},
2120 {MVAR_INVENTORY_POC_SECONDARY_NAME, 63},
2121 {MVAR_INVENTORY_POC_SECONDARY_EMAIL, 64},
2122 {MVAR_INVENTORY_POC_SECONDARY_PHONE_A, 65},
2123 {MVAR_INVENTORY_POC_SECONDARY_PHONE_B, 66},
2124 {MVAR_INVENTORY_POC_SECONDARY_CELL, 67},
2125 {MVAR_INVENTORY_POC_SECONDARY_SCREEN, 68},
2126 {MVAR_INVENTORY_POC_SECONDARY_NOTES, 69},
2127 {NULL}
2128 };
2129
2130 /******************************************************************************
2131 * *
2132 * Function: get_action_value *
2133 * *
2134 * Purpose: request action value by macro *
2135 * *
2136 * Return value: upon successful completion return SUCCEED *
2137 * otherwise FAIL *
2138 * *
2139 ******************************************************************************/
get_action_value(const char * macro,zbx_uint64_t actionid,char ** replace_to)2140 static int get_action_value(const char *macro, zbx_uint64_t actionid, char **replace_to)
2141 {
2142 int ret = SUCCEED;
2143
2144 if (0 == strcmp(macro, MVAR_ACTION_ID))
2145 {
2146 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, actionid);
2147 }
2148 else if (0 == strcmp(macro, MVAR_ACTION_NAME))
2149 {
2150 DB_RESULT result;
2151 DB_ROW row;
2152
2153 result = DBselect("select name from actions where actionid=" ZBX_FS_UI64, actionid);
2154
2155 if (NULL != (row = DBfetch(result)))
2156 *replace_to = zbx_strdup(*replace_to, row[0]);
2157 else
2158 ret = FAIL;
2159
2160 DBfree_result(result);
2161 }
2162
2163 return ret;
2164 }
2165
2166 /******************************************************************************
2167 * *
2168 * Function: get_host_inventory *
2169 * *
2170 * Purpose: request host inventory value by macro and trigger *
2171 * *
2172 * Return value: upon successful completion return SUCCEED *
2173 * otherwise FAIL *
2174 * *
2175 ******************************************************************************/
get_host_inventory(const char * macro,const char * expression,char ** replace_to,int N_functionid)2176 static int get_host_inventory(const char *macro, const char *expression, char **replace_to,
2177 int N_functionid)
2178 {
2179 int i;
2180
2181 for (i = 0; NULL != inventory_fields[i].macro; i++)
2182 {
2183 if (0 == strcmp(macro, inventory_fields[i].macro))
2184 {
2185 zbx_uint64_t itemid;
2186
2187 if (SUCCEED != get_N_itemid(expression, N_functionid, &itemid))
2188 return FAIL;
2189
2190 return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx);
2191 }
2192 }
2193
2194 return FAIL;
2195 }
2196
2197 /******************************************************************************
2198 * *
2199 * Function: get_host_inventory_by_itemid *
2200 * *
2201 * Purpose: request host inventory value by macro and itemid *
2202 * *
2203 * Return value: upon successful completion return SUCCEED *
2204 * otherwise FAIL *
2205 * *
2206 ******************************************************************************/
get_host_inventory_by_itemid(const char * macro,zbx_uint64_t itemid,char ** replace_to)2207 static int get_host_inventory_by_itemid(const char *macro, zbx_uint64_t itemid, char **replace_to)
2208 {
2209 int i;
2210
2211 for (i = 0; NULL != inventory_fields[i].macro; i++)
2212 {
2213 if (0 == strcmp(macro, inventory_fields[i].macro))
2214 return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx);
2215 }
2216
2217 return FAIL;
2218 }
2219
2220 /******************************************************************************
2221 * *
2222 * Function: compare_tags *
2223 * *
2224 * Purpose: comparison function to sort tags by tag/value *
2225 * *
2226 ******************************************************************************/
compare_tags(const void * d1,const void * d2)2227 static int compare_tags(const void *d1, const void *d2)
2228 {
2229 int ret;
2230
2231 const zbx_tag_t *tag1 = *(const zbx_tag_t **)d1;
2232 const zbx_tag_t *tag2 = *(const zbx_tag_t **)d2;
2233
2234 if (0 == (ret = zbx_strcmp_natural(tag1->tag, tag2->tag)))
2235 ret = zbx_strcmp_natural(tag1->value, tag2->value);
2236
2237 return ret;
2238 }
2239
2240 /******************************************************************************
2241 * *
2242 * Function: get_event_tags *
2243 * *
2244 * Purpose: format event tags string in format <tag1>[:<value1>], ... *
2245 * *
2246 * Parameters: event [IN] the event *
2247 * replace_to - [OUT] replacement string *
2248 * *
2249 ******************************************************************************/
get_event_tags(const DB_EVENT * event,char ** replace_to)2250 static void get_event_tags(const DB_EVENT *event, char **replace_to)
2251 {
2252 size_t replace_to_offset = 0, replace_to_alloc = 0;
2253 int i;
2254 zbx_vector_ptr_t tags;
2255
2256 if (0 == event->tags.values_num)
2257 {
2258 *replace_to = zbx_strdup(*replace_to, "");
2259 return;
2260 }
2261
2262 zbx_free(*replace_to);
2263
2264 /* copy tags to temporary vector for sorting */
2265
2266 zbx_vector_ptr_create(&tags);
2267 zbx_vector_ptr_reserve(&tags, event->tags.values_num);
2268
2269 for (i = 0; i < event->tags.values_num; i++)
2270 zbx_vector_ptr_append(&tags, event->tags.values[i]);
2271
2272 zbx_vector_ptr_sort(&tags, compare_tags);
2273
2274 for (i = 0; i < tags.values_num; i++)
2275 {
2276 const zbx_tag_t *tag = (const zbx_tag_t *)tags.values[i];
2277
2278 if (0 != i)
2279 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
2280
2281 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, tag->tag);
2282
2283 if ('\0' != *tag->value)
2284 {
2285 zbx_chrcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ':');
2286 zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, tag->value);
2287 }
2288 }
2289
2290 zbx_vector_ptr_destroy(&tags);
2291 }
2292
2293 /******************************************************************************
2294 * *
2295 * Function: get_recovery_event_value *
2296 * *
2297 * Purpose: request recovery event value by macro *
2298 * *
2299 ******************************************************************************/
get_recovery_event_value(const char * macro,const DB_EVENT * r_event,char ** replace_to)2300 static void get_recovery_event_value(const char *macro, const DB_EVENT *r_event, char **replace_to)
2301 {
2302 if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_DATE))
2303 {
2304 *replace_to = zbx_strdup(*replace_to, zbx_date2str(r_event->clock));
2305 }
2306 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_ID))
2307 {
2308 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, r_event->eventid);
2309 }
2310 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_STATUS))
2311 {
2312 *replace_to = zbx_strdup(*replace_to,
2313 zbx_event_value_string(r_event->source, r_event->object, r_event->value));
2314 }
2315 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_TIME))
2316 {
2317 *replace_to = zbx_strdup(*replace_to, zbx_time2str(r_event->clock));
2318 }
2319 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_VALUE))
2320 {
2321 *replace_to = zbx_dsprintf(*replace_to, "%d", r_event->value);
2322 }
2323 else if (EVENT_SOURCE_TRIGGERS == r_event->source && 0 == strcmp(macro, MVAR_EVENT_RECOVERY_TAGS))
2324 {
2325 get_event_tags(r_event, replace_to);
2326 }
2327 else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_NAME))
2328 {
2329 *replace_to = zbx_dsprintf(*replace_to, "%s", r_event->name);
2330 }
2331 }
2332
2333 /******************************************************************************
2334 * *
2335 * Function: get_current_event_value *
2336 * *
2337 * Purpose: request current event value by macro *
2338 * *
2339 ******************************************************************************/
get_current_event_value(const char * macro,const DB_EVENT * event,char ** replace_to)2340 static void get_current_event_value(const char *macro, const DB_EVENT *event, char **replace_to)
2341 {
2342 if (0 == strcmp(macro, MVAR_EVENT_STATUS))
2343 {
2344 *replace_to = zbx_strdup(*replace_to,
2345 zbx_event_value_string(event->source, event->object, event->value));
2346 }
2347 else if (0 == strcmp(macro, MVAR_EVENT_VALUE))
2348 {
2349 *replace_to = zbx_dsprintf(*replace_to, "%d", event->value);
2350 }
2351 }
2352
2353 /******************************************************************************
2354 * *
2355 * Function: get_event_value *
2356 * *
2357 * Purpose: request event value by macro *
2358 * *
2359 ******************************************************************************/
get_event_value(const char * macro,const DB_EVENT * event,char ** replace_to,const zbx_uint64_t * recipient_userid)2360 static void get_event_value(const char *macro, const DB_EVENT *event, char **replace_to,
2361 const zbx_uint64_t *recipient_userid)
2362 {
2363 if (0 == strcmp(macro, MVAR_EVENT_AGE))
2364 {
2365 *replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - event->clock));
2366 }
2367 else if (0 == strcmp(macro, MVAR_EVENT_DATE))
2368 {
2369 *replace_to = zbx_strdup(*replace_to, zbx_date2str(event->clock));
2370 }
2371 else if (0 == strcmp(macro, MVAR_EVENT_ID))
2372 {
2373 *replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, event->eventid);
2374 }
2375 else if (0 == strcmp(macro, MVAR_EVENT_TIME))
2376 {
2377 *replace_to = zbx_strdup(*replace_to, zbx_time2str(event->clock));
2378 }
2379 else if (EVENT_SOURCE_TRIGGERS == event->source)
2380 {
2381 if (0 == strcmp(macro, MVAR_EVENT_ACK_HISTORY) || 0 == strcmp(macro, MVAR_EVENT_UPDATE_HISTORY))
2382 {
2383 get_event_update_history(event, replace_to, recipient_userid);
2384 }
2385 else if (0 == strcmp(macro, MVAR_EVENT_ACK_STATUS))
2386 {
2387 *replace_to = zbx_strdup(*replace_to, event->acknowledged ? "Yes" : "No");
2388 }
2389 else if (0 == strcmp(macro, MVAR_EVENT_TAGS))
2390 {
2391 get_event_tags(event, replace_to);
2392 }
2393 else if (0 == strcmp(macro, MVAR_EVENT_NSEVERITY))
2394 {
2395 *replace_to = zbx_dsprintf(*replace_to, "%d", (int)event->severity);
2396 }
2397 else if (0 == strcmp(macro, MVAR_EVENT_SEVERITY))
2398 {
2399 if (FAIL == get_trigger_severity_name(event->severity, replace_to))
2400 *replace_to = zbx_strdup(*replace_to, "unknown");
2401 }
2402 }
2403 }
2404
2405 /******************************************************************************
2406 * *
2407 * Function: is_indexed_macro *
2408 * *
2409 * Purpose: check if a token contains indexed macro *
2410 * *
2411 ******************************************************************************/
is_indexed_macro(const char * str,const zbx_token_t * token)2412 static int is_indexed_macro(const char *str, const zbx_token_t *token)
2413 {
2414 const char *p;
2415
2416 switch (token->type)
2417 {
2418 case ZBX_TOKEN_MACRO:
2419 p = str + token->loc.r - 1;
2420 break;
2421 case ZBX_TOKEN_FUNC_MACRO:
2422 p = str + token->data.func_macro.macro.r - 1;
2423 break;
2424 default:
2425 THIS_SHOULD_NEVER_HAPPEN;
2426 return FAIL;
2427 }
2428
2429 return '1' <= *p && *p <= '9' ? 1 : 0;
2430 }
2431
2432 /******************************************************************************
2433 * *
2434 * Function: macro_in_list *
2435 * *
2436 * Purpose: check if a macro in string is one of the list and extract index *
2437 * *
2438 * Parameters: str - [IN] string containing potential macro *
2439 * strloc - [IN] part of the string to check *
2440 * macros - [IN] list of allowed macros (without indices) *
2441 * N_functionid - [OUT] index of the macro in string (if valid) *
2442 * *
2443 * Return value: unindexed macro from the allowed list or NULL *
2444 * *
2445 * Comments: example: N_functionid is untouched if function returns NULL, for *
2446 * a valid unindexed macro N_function is 1. *
2447 * *
2448 ******************************************************************************/
macro_in_list(const char * str,zbx_strloc_t strloc,const char ** macros,int * N_functionid)2449 static const char *macro_in_list(const char *str, zbx_strloc_t strloc, const char **macros, int *N_functionid)
2450 {
2451 const char **macro, *m;
2452 size_t i;
2453
2454 for (macro = macros; NULL != *macro; macro++)
2455 {
2456 for (m = *macro, i = strloc.l; '\0' != *m && i <= strloc.r && str[i] == *m; m++, i++)
2457 ;
2458
2459 /* check whether macro has ended while strloc hasn't or vice-versa */
2460 if (('\0' == *m && i <= strloc.r) || ('\0' != *m && i > strloc.r))
2461 continue;
2462
2463 /* strloc either fully matches macro... */
2464 if ('\0' == *m)
2465 {
2466 if (NULL != N_functionid)
2467 *N_functionid = 1;
2468
2469 break;
2470 }
2471
2472 /* ...or there is a mismatch, check if it's in a pre-last character and it's an index */
2473 if (i == strloc.r - 1 && '1' <= str[i] && str[i] <= '9' && str[i + 1] == *m && '\0' == *(m + 1))
2474 {
2475 if (NULL != N_functionid)
2476 *N_functionid = str[i] - '0';
2477
2478 break;
2479 }
2480 }
2481
2482 return *macro;
2483 }
2484
2485 /******************************************************************************
2486 * *
2487 * Function: get_trigger_function_value *
2488 * *
2489 * Purpose: trying to evaluate a trigger function *
2490 * *
2491 * Parameters: expression - [IN] trigger expression, source of hostnames and *
2492 * item keys for {HOST.HOST} and {ITEM.KEY} macros *
2493 * replace_to - [OUT] evaluation result *
2494 * data - [IN] string containing simple macro *
2495 * macro - [IN] simple macro token location in string *
2496 * *
2497 * Return value: SUCCEED - successfully evaluated or invalid macro(s) in host *
2498 * and/or item key positions (in the latter case *
2499 * replace_to remains unchanged and simple macro *
2500 * shouldn't be replaced with anything) *
2501 * FAIL - evaluation failed and macro has to be replaced *
2502 * with STR_UNKNOWN_VARIABLE ("*UNKNOWN*") *
2503 * *
2504 * Author: Alexander Vladishev *
2505 * *
2506 * Comments: example: " {Zabbix server:{ITEM.KEY1}.last(0)} " to " 1.34 " *
2507 * *
2508 ******************************************************************************/
get_trigger_function_value(const char * expression,char ** replace_to,char * data,const zbx_token_simple_macro_t * simple_macro)2509 static int get_trigger_function_value(const char *expression, char **replace_to, char *data,
2510 const zbx_token_simple_macro_t *simple_macro)
2511 {
2512 char *host = NULL, *key = NULL;
2513 int N_functionid, ret = FAIL;
2514
2515 if (NULL != macro_in_list(data, simple_macro->host, simple_host_macros, &N_functionid))
2516 {
2517 if (SUCCEED != DBget_trigger_value(expression, &host, N_functionid, ZBX_REQUEST_HOST_HOST))
2518 goto out;
2519 }
2520
2521 if (NULL != macro_in_list(data, simple_macro->key, simple_key_macros, &N_functionid))
2522 {
2523 if (SUCCEED != DBget_trigger_value(expression, &key, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG))
2524 goto out;
2525 }
2526
2527 data[simple_macro->host.r + 1] = '\0';
2528 data[simple_macro->key.r + 1] = '\0';
2529 data[simple_macro->func_param.l] = '\0';
2530 data[simple_macro->func_param.r] = '\0';
2531
2532 ret = evaluate_macro_function(replace_to, (NULL == host ? data + simple_macro->host.l : host),
2533 (NULL == key ? data + simple_macro->key.l : key), data + simple_macro->func.l,
2534 data + simple_macro->func_param.l + 1);
2535
2536 data[simple_macro->host.r + 1] = ':';
2537 data[simple_macro->key.r + 1] = '.';
2538 data[simple_macro->func_param.l] = '(';
2539 data[simple_macro->func_param.r] = ')';
2540 out:
2541 zbx_free(host);
2542 zbx_free(key);
2543
2544 return ret;
2545 }
2546
2547 /******************************************************************************
2548 * *
2549 * Function: cache_trigger_hostids *
2550 * *
2551 * Purpose: cache host identifiers referenced by trigger expression *
2552 * *
2553 * Parameters: hostids - [OUT] the host identifier cache *
2554 * expression - [IN] the trigger expression *
2555 * recovery_expression - [IN] the trigger recovery expression *
2556 * (can be empty) *
2557 * *
2558 ******************************************************************************/
cache_trigger_hostids(zbx_vector_uint64_t * hostids,const char * expression,const char * recovery_expression)2559 static void cache_trigger_hostids(zbx_vector_uint64_t *hostids, const char *expression,
2560 const char *recovery_expression)
2561 {
2562 if (0 == hostids->values_num)
2563 {
2564 zbx_vector_uint64_t functionids;
2565
2566 zbx_vector_uint64_create(&functionids);
2567 get_functionids(&functionids, expression);
2568 get_functionids(&functionids, recovery_expression);
2569 DCget_hostids_by_functionids(&functionids, hostids);
2570 zbx_vector_uint64_destroy(&functionids);
2571 }
2572 }
2573
2574 /******************************************************************************
2575 * *
2576 * Function: cache_item_hostid *
2577 * *
2578 * Purpose: cache host identifier referenced by an item or a lld-rule *
2579 * *
2580 * Parameters: hostids - [OUT] the host identifier cache *
2581 * itemid - [IN] the item identifier *
2582 * *
2583 ******************************************************************************/
cache_item_hostid(zbx_vector_uint64_t * hostids,zbx_uint64_t itemid)2584 static void cache_item_hostid(zbx_vector_uint64_t *hostids, zbx_uint64_t itemid)
2585 {
2586 if (0 == hostids->values_num)
2587 {
2588 DC_ITEM item;
2589 int errcode;
2590
2591 DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
2592
2593 if (SUCCEED == errcode)
2594 zbx_vector_uint64_append(hostids, item.host.hostid);
2595
2596 DCconfig_clean_items(&item, &errcode, 1);
2597 }
2598 }
2599
2600 /******************************************************************************
2601 * *
2602 * Function: wrap_negative_double_suffix *
2603 * *
2604 * Purpose: wrap a replacement string that represents a negative number in *
2605 * parentheses (for instance, turn "-123.456M" into "(-123.456M)") *
2606 * *
2607 * Parameters: replace_to - [IN/OUT] replacement string *
2608 * replace_to_alloc - [IN/OUT] number of allocated bytes *
2609 * *
2610 ******************************************************************************/
wrap_negative_double_suffix(char ** replace_to,size_t * replace_to_alloc)2611 static void wrap_negative_double_suffix(char **replace_to, size_t *replace_to_alloc)
2612 {
2613 size_t replace_to_len;
2614
2615 if ('-' != (*replace_to)[0])
2616 return;
2617
2618 replace_to_len = strlen(*replace_to);
2619
2620 if (NULL != replace_to_alloc && *replace_to_alloc >= replace_to_len + 3)
2621 {
2622 memmove(*replace_to + 1, *replace_to, replace_to_len);
2623 }
2624 else
2625 {
2626 char *buffer;
2627
2628 if (NULL != replace_to_alloc)
2629 *replace_to_alloc = replace_to_len + 3;
2630
2631 buffer = (char *)zbx_malloc(NULL, replace_to_len + 3);
2632
2633 memcpy(buffer + 1, *replace_to, replace_to_len);
2634
2635 zbx_free(*replace_to);
2636 *replace_to = buffer;
2637 }
2638
2639 (*replace_to)[0] = '(';
2640 (*replace_to)[replace_to_len + 1] = ')';
2641 (*replace_to)[replace_to_len + 2] = '\0';
2642 }
2643
zbx_dobject_status2str(int st)2644 static const char *zbx_dobject_status2str(int st)
2645 {
2646 switch (st)
2647 {
2648 case DOBJECT_STATUS_UP:
2649 return "UP";
2650 case DOBJECT_STATUS_DOWN:
2651 return "DOWN";
2652 case DOBJECT_STATUS_DISCOVER:
2653 return "DISCOVERED";
2654 case DOBJECT_STATUS_LOST:
2655 return "LOST";
2656 default:
2657 return "UNKNOWN";
2658 }
2659 }
2660
2661 /******************************************************************************
2662 * *
2663 * Function: substitute_simple_macros *
2664 * *
2665 * Purpose: substitute simple macros in data string with real values *
2666 * *
2667 * Author: Eugene Grigorjev *
2668 * *
2669 ******************************************************************************/
substitute_simple_macros(zbx_uint64_t * actionid,const DB_EVENT * event,const DB_EVENT * r_event,zbx_uint64_t * userid,const zbx_uint64_t * hostid,const DC_HOST * dc_host,const DC_ITEM * dc_item,DB_ALERT * alert,const DB_ACKNOWLEDGE * ack,char ** data,int macro_type,char * error,int maxerrlen)2670 int substitute_simple_macros(zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event,
2671 zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item,
2672 DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, char **data, int macro_type, char *error, int maxerrlen)
2673 {
2674 const char *__function_name = "substitute_simple_macros";
2675
2676 char c, *replace_to = NULL, sql[64];
2677 const char *m, *replace = NULL;
2678 int N_functionid, indexed_macro, require_numeric, require_address, ret, res = SUCCEED,
2679 pos = 0, found,
2680 raw_value;
2681 size_t data_alloc, data_len, replace_len;
2682 DC_INTERFACE interface;
2683 zbx_vector_uint64_t hostids;
2684 zbx_token_t token;
2685 zbx_token_search_t token_search;
2686 char *expression = NULL;
2687
2688 if (NULL == data || NULL == *data || '\0' == **data)
2689 {
2690 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:EMPTY", __function_name);
2691 return res;
2692 }
2693
2694 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, *data);
2695
2696 if (0 != (macro_type & MACRO_TYPE_TRIGGER_DESCRIPTION))
2697 token_search = ZBX_TOKEN_SEARCH_REFERENCES;
2698 else
2699 token_search = ZBX_TOKEN_SEARCH_BASIC;
2700
2701 if (SUCCEED != zbx_token_find(*data, pos, &token, token_search))
2702 return res;
2703
2704 zbx_vector_uint64_create(&hostids);
2705
2706 data_alloc = data_len = strlen(*data) + 1;
2707
2708 for (found = SUCCEED; SUCCEED == res && SUCCEED == found;
2709 found = zbx_token_find(*data, pos, &token, token_search))
2710 {
2711 indexed_macro = 0;
2712 require_numeric = 0;
2713 require_address = 0;
2714 N_functionid = 1;
2715 raw_value = 0;
2716 pos = token.loc.l;
2717
2718 switch (token.type)
2719 {
2720 case ZBX_TOKEN_OBJECTID:
2721 case ZBX_TOKEN_LLD_MACRO:
2722 case ZBX_TOKEN_LLD_FUNC_MACRO:
2723 /* neither lld or {123123} macros are processed by this function, skip them */
2724 pos = token.loc.r + 1;
2725 continue;
2726 case ZBX_TOKEN_MACRO:
2727 if (0 == (indexed_macro = is_indexed_macro(*data, &token)))
2728 {
2729 /* Theoretically we could do m = macro_in_list() here as well to validate */
2730 /* token and get unindexed macro equivalent, but it will be a double work */
2731 /* since we will pass m through a lot of strcmp(m, MVAR_*) checks anyway, */
2732 /* plus ex_macros is a long list. For now, we rely on this surgery. */
2733 m = *data + token.loc.l;
2734 c = (*data)[token.loc.r + 1];
2735 (*data)[token.loc.r + 1] = '\0';
2736 }
2737 else if (NULL == (m = macro_in_list(*data, token.loc, ex_macros, &N_functionid)))
2738 {
2739 pos = token.loc.r + 1;
2740 continue;
2741 }
2742 break;
2743 case ZBX_TOKEN_FUNC_MACRO:
2744 raw_value = 1;
2745 indexed_macro = is_indexed_macro(*data, &token);
2746 if (NULL == (m = macro_in_list(*data, token.data.func_macro.macro, mod_macros,
2747 &N_functionid)))
2748 {
2749 /* Ignore functions with macros not supporting them, but do not skip the */
2750 /* whole token, nested macro should be resolved in this case. */
2751 pos++;
2752 continue;
2753 }
2754 break;
2755 case ZBX_TOKEN_USER_MACRO:
2756 /* To avoid *data modification DCget_user_macro() should be replaced with a function */
2757 /* that takes initial *data string and token.data.user_macro instead of m as params. */
2758 m = *data + token.loc.l;
2759 c = (*data)[token.loc.r + 1];
2760 (*data)[token.loc.r + 1] = '\0';
2761 break;
2762 case ZBX_TOKEN_SIMPLE_MACRO:
2763 if (0 == (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
2764 MACRO_TYPE_MESSAGE_ACK)) ||
2765 EVENT_SOURCE_TRIGGERS != ((NULL != r_event) ? r_event : event)->source)
2766 {
2767 pos++;
2768 continue;
2769 }
2770 /* These macros (and probably all other in the future) must be resolved using only */
2771 /* information stored in token.data union. For now, force crash if they rely on m. */
2772 m = NULL;
2773 break;
2774 case ZBX_TOKEN_REFERENCE:
2775 /* These macros (and probably all other in the future) must be resolved using only */
2776 /* information stored in token.data union. For now, force crash if they rely on m. */
2777 m = NULL;
2778 break;
2779 default:
2780 THIS_SHOULD_NEVER_HAPPEN;
2781 res = FAIL;
2782 continue;
2783 }
2784
2785 ret = SUCCEED;
2786
2787 if (0 != (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
2788 MACRO_TYPE_MESSAGE_ACK)))
2789 {
2790 const DB_EVENT *c_event;
2791
2792 c_event = ((NULL != r_event) ? r_event : event);
2793
2794 if (EVENT_SOURCE_TRIGGERS == c_event->source)
2795 {
2796 if (ZBX_TOKEN_USER_MACRO == token.type)
2797 {
2798 cache_trigger_hostids(&hostids, c_event->trigger.expression,
2799 c_event->trigger.recovery_expression);
2800 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
2801 pos = token.loc.r;
2802 }
2803 else if (ZBX_TOKEN_SIMPLE_MACRO == token.type)
2804 {
2805 ret = get_trigger_function_value(c_event->trigger.expression, &replace_to,
2806 *data, &token.data.simple_macro);
2807 }
2808 else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
2809 {
2810 ret = get_action_value(m, *actionid, &replace_to);
2811 }
2812 else if (0 == strcmp(m, MVAR_DATE))
2813 {
2814 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
2815 }
2816 else if (0 == strcmp(m, MVAR_ESC_HISTORY))
2817 {
2818 get_escalation_history(*actionid, event, r_event, &replace_to, userid);
2819 }
2820 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
2821 {
2822 if (NULL != r_event)
2823 get_recovery_event_value(m, r_event, &replace_to);
2824 }
2825 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
2826 {
2827 get_current_event_value(m, c_event, &replace_to);
2828 }
2829 else if (0 == strcmp(m, MVAR_EVENT_NAME))
2830 {
2831 replace_to = zbx_strdup(replace_to, event->name);
2832 }
2833 else if (0 == strcmp(m, MVAR_ACK_MESSAGE) || 0 == strcmp(m, MVAR_EVENT_UPDATE_MESSAGE))
2834 {
2835 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2836 replace_to = zbx_strdup(replace_to, ack->message);
2837 }
2838 else if (0 == strcmp(m, MVAR_ACK_TIME) || 0 == strcmp(m, MVAR_EVENT_UPDATE_TIME))
2839 {
2840 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2841 replace_to = zbx_strdup(replace_to, zbx_time2str(ack->clock));
2842 }
2843 else if (0 == strcmp(m, MVAR_ACK_DATE) || 0 == strcmp(m, MVAR_EVENT_UPDATE_DATE))
2844 {
2845 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2846 replace_to = zbx_strdup(replace_to, zbx_date2str(ack->clock));
2847 }
2848 else if (0 == strcmp(m, MVAR_EVENT_UPDATE_ACTION))
2849 {
2850 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2851 {
2852 get_problem_update_actions(ack, ZBX_PROBLEM_UPDATE_ACKNOWLEDGE |
2853 ZBX_PROBLEM_UPDATE_CLOSE | ZBX_PROBLEM_UPDATE_MESSAGE |
2854 ZBX_PROBLEM_UPDATE_SEVERITY, &replace_to);
2855 }
2856 }
2857 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
2858 {
2859 get_event_value(m, event, &replace_to, userid);
2860 }
2861 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
2862 {
2863 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2864 N_functionid, ZBX_REQUEST_HOST_HOST);
2865 }
2866 else if (0 == strcmp(m, MVAR_HOST_NAME))
2867 {
2868 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2869 N_functionid, ZBX_REQUEST_HOST_NAME);
2870 }
2871 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
2872 {
2873 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2874 N_functionid, ZBX_REQUEST_HOST_DESCRIPTION);
2875 }
2876 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
2877 {
2878 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2879 N_functionid, ZBX_REQUEST_HOST_IP);
2880 }
2881 else if (0 == strcmp(m, MVAR_HOST_DNS))
2882 {
2883 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2884 N_functionid, ZBX_REQUEST_HOST_DNS);
2885 }
2886 else if (0 == strcmp(m, MVAR_HOST_CONN))
2887 {
2888 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2889 N_functionid, ZBX_REQUEST_HOST_CONN);
2890 }
2891 else if (0 == strcmp(m, MVAR_HOST_PORT))
2892 {
2893 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2894 N_functionid, ZBX_REQUEST_HOST_PORT);
2895 }
2896 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
2897 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
2898 {
2899 ret = get_host_inventory(m, c_event->trigger.expression, &replace_to,
2900 N_functionid);
2901 }
2902 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
2903 {
2904 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2905 N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION);
2906 }
2907 else if (0 == strcmp(m, MVAR_ITEM_ID))
2908 {
2909 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2910 N_functionid, ZBX_REQUEST_ITEM_ID);
2911 }
2912 else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
2913 {
2914 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2915 N_functionid, ZBX_REQUEST_ITEM_KEY);
2916 }
2917 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
2918 {
2919 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2920 N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG);
2921 }
2922 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
2923 {
2924 ret = DBitem_lastvalue(c_event->trigger.expression, &replace_to, N_functionid,
2925 raw_value);
2926 }
2927 else if (0 == strcmp(m, MVAR_ITEM_LOG_AGE))
2928 {
2929 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2930 N_functionid, ZBX_REQUEST_ITEM_LOG_AGE, c_event->clock,
2931 c_event->ns);
2932 }
2933 else if (0 == strcmp(m, MVAR_ITEM_LOG_DATE))
2934 {
2935 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2936 N_functionid, ZBX_REQUEST_ITEM_LOG_DATE, c_event->clock,
2937 c_event->ns);
2938 }
2939 else if (0 == strcmp(m, MVAR_ITEM_LOG_EVENTID))
2940 {
2941 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2942 N_functionid, ZBX_REQUEST_ITEM_LOG_EVENTID, c_event->clock,
2943 c_event->ns);
2944 }
2945 else if (0 == strcmp(m, MVAR_ITEM_LOG_NSEVERITY))
2946 {
2947 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2948 N_functionid, ZBX_REQUEST_ITEM_LOG_NSEVERITY, c_event->clock,
2949 c_event->ns);
2950 }
2951 else if (0 == strcmp(m, MVAR_ITEM_LOG_SEVERITY))
2952 {
2953 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2954 N_functionid, ZBX_REQUEST_ITEM_LOG_SEVERITY, c_event->clock,
2955 c_event->ns);
2956 }
2957 else if (0 == strcmp(m, MVAR_ITEM_LOG_SOURCE))
2958 {
2959 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2960 N_functionid, ZBX_REQUEST_ITEM_LOG_SOURCE, c_event->clock,
2961 c_event->ns);
2962 }
2963 else if (0 == strcmp(m, MVAR_ITEM_LOG_TIME))
2964 {
2965 ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2966 N_functionid, ZBX_REQUEST_ITEM_LOG_TIME, c_event->clock,
2967 c_event->ns);
2968 }
2969 else if (0 == strcmp(m, MVAR_ITEM_NAME))
2970 {
2971 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2972 N_functionid, ZBX_REQUEST_ITEM_NAME);
2973 }
2974 else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
2975 {
2976 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2977 N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG);
2978 }
2979 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
2980 {
2981 ret = DBitem_value(c_event->trigger.expression, &replace_to, N_functionid,
2982 c_event->clock, c_event->ns, raw_value);
2983 }
2984 else if (0 == strcmp(m, MVAR_PROXY_NAME))
2985 {
2986 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2987 N_functionid, ZBX_REQUEST_PROXY_NAME);
2988 }
2989 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
2990 {
2991 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2992 N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
2993 }
2994 else if (0 == strcmp(m, MVAR_TIME))
2995 {
2996 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
2997 }
2998 else if (0 == strcmp(m, MVAR_TRIGGER_DESCRIPTION) ||
2999 0 == strcmp(m, MVAR_TRIGGER_COMMENT))
3000 {
3001 replace_to = zbx_strdup(replace_to, c_event->trigger.comments);
3002 substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3003 NULL, &replace_to, MACRO_TYPE_TRIGGER_COMMENTS, error,
3004 maxerrlen);
3005 }
3006 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_ACK))
3007 {
3008 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 0, 1);
3009 }
3010 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_PROBLEM_ACK))
3011 {
3012 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 1, 1);
3013 }
3014 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_PROBLEM_UNACK))
3015 {
3016 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 1, 0);
3017 }
3018 else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_UNACK))
3019 {
3020 ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 0, 0);
3021 }
3022 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION))
3023 {
3024 replace_to = zbx_strdup(replace_to, c_event->trigger.expression);
3025 DCexpand_trigger_expression(&replace_to);
3026 }
3027 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION_RECOVERY))
3028 {
3029 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == c_event->trigger.recovery_mode)
3030 {
3031 replace_to = zbx_strdup(replace_to,
3032 c_event->trigger.recovery_expression);
3033 DCexpand_trigger_expression(&replace_to);
3034 }
3035 else
3036 replace_to = zbx_strdup(replace_to, "");
3037 }
3038 else if (0 == strcmp(m, MVAR_TRIGGER_HOSTGROUP_NAME))
3039 {
3040 ret = DBget_trigger_hostgroup_name(c_event->objectid, userid, &replace_to);
3041 }
3042 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3043 {
3044 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3045 }
3046 else if (0 == strcmp(m, MVAR_TRIGGER_NAME))
3047 {
3048 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3049 substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3050 NULL, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION, error,
3051 maxerrlen);
3052 }
3053 else if (0 == strcmp(m, MVAR_TRIGGER_NAME_ORIG))
3054 {
3055 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3056 }
3057 else if (0 == strcmp(m, MVAR_TRIGGER_NSEVERITY))
3058 {
3059 replace_to = zbx_dsprintf(replace_to, "%d", (int)c_event->trigger.priority);
3060 }
3061 else if (0 == strcmp(m, MVAR_TRIGGER_STATUS) || 0 == strcmp(m, MVAR_STATUS))
3062 {
3063 replace_to = zbx_strdup(replace_to,
3064 zbx_trigger_value_string(c_event->trigger.value));
3065 }
3066 else if (0 == strcmp(m, MVAR_TRIGGER_SEVERITY))
3067 {
3068 ret = get_trigger_severity_name(c_event->trigger.priority, &replace_to);
3069 }
3070 else if (0 == strcmp(m, MVAR_TRIGGER_TEMPLATE_NAME))
3071 {
3072 ret = DBget_trigger_template_name(c_event->objectid, userid, &replace_to);
3073 }
3074 else if (0 == strcmp(m, MVAR_TRIGGER_URL))
3075 {
3076 replace_to = zbx_strdup(replace_to, c_event->trigger.url);
3077 substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3078 NULL, &replace_to, MACRO_TYPE_TRIGGER_URL, error, maxerrlen);
3079 }
3080 else if (0 == strcmp(m, MVAR_TRIGGER_VALUE))
3081 {
3082 replace_to = zbx_dsprintf(replace_to, "%d", c_event->trigger.value);
3083 }
3084 else if (0 == strcmp(m, MVAR_USER_FULLNAME))
3085 {
3086 if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
3087 {
3088 const char *user_name;
3089
3090 if (SUCCEED == zbx_check_user_permissions(&ack->userid, userid))
3091 user_name = zbx_user_string(ack->userid);
3092 else
3093 user_name = "Inaccessible user";
3094
3095 replace_to = zbx_strdup(replace_to, user_name);
3096 }
3097 }
3098 }
3099 else if (EVENT_SOURCE_INTERNAL == c_event->source && EVENT_OBJECT_TRIGGER == c_event->object)
3100 {
3101 if (ZBX_TOKEN_USER_MACRO == token.type)
3102 {
3103 cache_trigger_hostids(&hostids, c_event->trigger.expression,
3104 c_event->trigger.recovery_expression);
3105 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3106 pos = token.loc.r;
3107 }
3108 else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3109 {
3110 ret = get_action_value(m, *actionid, &replace_to);
3111 }
3112 else if (0 == strcmp(m, MVAR_DATE))
3113 {
3114 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3115 }
3116 else if (0 == strcmp(m, MVAR_ESC_HISTORY))
3117 {
3118 get_escalation_history(*actionid, event, r_event, &replace_to, userid);
3119 }
3120 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3121 {
3122 if (NULL != r_event)
3123 get_recovery_event_value(m, r_event, &replace_to);
3124 }
3125 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3126 {
3127 get_current_event_value(m, c_event, &replace_to);
3128 }
3129 else if (0 == strcmp(m, MVAR_EVENT_NAME))
3130 {
3131 replace_to = zbx_strdup(replace_to, event->name);
3132 }
3133 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3134 {
3135 get_event_value(m, event, &replace_to, userid);
3136 }
3137 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3138 {
3139 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3140 N_functionid, ZBX_REQUEST_HOST_HOST);
3141 }
3142 else if (0 == strcmp(m, MVAR_HOST_NAME))
3143 {
3144 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3145 N_functionid, ZBX_REQUEST_HOST_NAME);
3146 }
3147 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3148 {
3149 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3150 N_functionid, ZBX_REQUEST_HOST_DESCRIPTION);
3151 }
3152 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3153 {
3154 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3155 N_functionid, ZBX_REQUEST_HOST_IP);
3156 }
3157 else if (0 == strcmp(m, MVAR_HOST_DNS))
3158 {
3159 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3160 N_functionid, ZBX_REQUEST_HOST_DNS);
3161 }
3162 else if (0 == strcmp(m, MVAR_HOST_CONN))
3163 {
3164 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3165 N_functionid, ZBX_REQUEST_HOST_CONN);
3166 }
3167 else if (0 == strcmp(m, MVAR_HOST_PORT))
3168 {
3169 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3170 N_functionid, ZBX_REQUEST_HOST_PORT);
3171 }
3172 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3173 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3174 {
3175 ret = get_host_inventory(m, c_event->trigger.expression, &replace_to,
3176 N_functionid);
3177 }
3178 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3179 {
3180 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3181 N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION);
3182 }
3183 else if (0 == strcmp(m, MVAR_ITEM_ID))
3184 {
3185 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3186 N_functionid, ZBX_REQUEST_ITEM_ID);
3187 }
3188 else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3189 {
3190 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3191 N_functionid, ZBX_REQUEST_ITEM_KEY);
3192 }
3193 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3194 {
3195 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3196 N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG);
3197 }
3198 else if (0 == strcmp(m, MVAR_ITEM_NAME))
3199 {
3200 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3201 N_functionid, ZBX_REQUEST_ITEM_NAME);
3202 }
3203 else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3204 {
3205 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3206 N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG);
3207 }
3208 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3209 {
3210 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3211 N_functionid, ZBX_REQUEST_PROXY_NAME);
3212 }
3213 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3214 {
3215 ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3216 N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
3217 }
3218 else if (0 == strcmp(m, MVAR_TIME))
3219 {
3220 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3221 }
3222 else if (0 == strcmp(m, MVAR_TRIGGER_DESCRIPTION) ||
3223 0 == strcmp(m, MVAR_TRIGGER_COMMENT))
3224 {
3225 replace_to = zbx_strdup(replace_to, c_event->trigger.comments);
3226 substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3227 NULL, &replace_to, MACRO_TYPE_TRIGGER_COMMENTS, error,
3228 maxerrlen);
3229 }
3230 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION))
3231 {
3232 replace_to = zbx_strdup(replace_to, c_event->trigger.expression);
3233 DCexpand_trigger_expression(&replace_to);
3234 }
3235 else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION_RECOVERY))
3236 {
3237 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == c_event->trigger.recovery_mode)
3238 {
3239 replace_to = zbx_strdup(replace_to,
3240 c_event->trigger.recovery_expression);
3241 DCexpand_trigger_expression(&replace_to);
3242 }
3243 else
3244 replace_to = zbx_strdup(replace_to, "");
3245 }
3246 else if (0 == strcmp(m, MVAR_TRIGGER_HOSTGROUP_NAME))
3247 {
3248 ret = DBget_trigger_hostgroup_name(c_event->objectid, userid, &replace_to);
3249 }
3250 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3251 {
3252 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3253 }
3254 else if (0 == strcmp(m, MVAR_TRIGGER_NAME))
3255 {
3256 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3257 substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3258 NULL, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION, error,
3259 maxerrlen);
3260 }
3261 else if (0 == strcmp(m, MVAR_TRIGGER_NAME_ORIG))
3262 {
3263 replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3264 }
3265 else if (0 == strcmp(m, MVAR_TRIGGER_NSEVERITY))
3266 {
3267 replace_to = zbx_dsprintf(replace_to, "%d", (int)c_event->trigger.priority);
3268 }
3269 else if (0 == strcmp(m, MVAR_TRIGGER_SEVERITY))
3270 {
3271 ret = get_trigger_severity_name(c_event->trigger.priority, &replace_to);
3272 }
3273 else if (0 == strcmp(m, MVAR_TRIGGER_STATE))
3274 {
3275 replace_to = zbx_strdup(replace_to, zbx_trigger_state_string(c_event->value));
3276 }
3277 else if (0 == strcmp(m, MVAR_TRIGGER_TEMPLATE_NAME))
3278 {
3279 ret = DBget_trigger_template_name(c_event->objectid, userid, &replace_to);
3280 }
3281 else if (0 == strcmp(m, MVAR_TRIGGER_URL))
3282 {
3283 replace_to = zbx_strdup(replace_to, c_event->trigger.url);
3284 substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3285 NULL, &replace_to, MACRO_TYPE_TRIGGER_URL, error, maxerrlen);
3286 }
3287 }
3288 else if (0 == indexed_macro && EVENT_SOURCE_DISCOVERY == c_event->source)
3289 {
3290 if (ZBX_TOKEN_USER_MACRO == token.type)
3291 {
3292 DCget_user_macro(NULL, 0, m, &replace_to);
3293 pos = token.loc.r;
3294 }
3295 else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3296 {
3297 ret = get_action_value(m, *actionid, &replace_to);
3298 }
3299 else if (0 == strcmp(m, MVAR_DATE))
3300 {
3301 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3302 }
3303 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3304 {
3305 get_event_value(m, event, &replace_to, userid);
3306 }
3307 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_IPADDRESS))
3308 {
3309 ret = DBget_dhost_value_by_event(c_event, &replace_to, "s.ip");
3310 }
3311 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_DNS))
3312 {
3313 ret = DBget_dhost_value_by_event(c_event, &replace_to, "s.dns");
3314 }
3315 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_STATUS))
3316 {
3317 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3318 "h.status")))
3319 {
3320 replace_to = zbx_strdup(replace_to,
3321 zbx_dobject_status2str(atoi(replace_to)));
3322 }
3323 }
3324 else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_UPTIME))
3325 {
3326 zbx_snprintf(sql, sizeof(sql),
3327 "case when h.status=%d then h.lastup else h.lastdown end",
3328 DOBJECT_STATUS_UP);
3329 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to, sql)))
3330 {
3331 replace_to = zbx_strdup(replace_to,
3332 zbx_age2str(time(NULL) - atoi(replace_to)));
3333 }
3334 }
3335 else if (0 == strcmp(m, MVAR_DISCOVERY_RULE_NAME))
3336 {
3337 ret = DBget_drule_value_by_event(c_event, &replace_to, "name");
3338 }
3339 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_NAME))
3340 {
3341 if (SUCCEED == (ret = DBget_dchecks_value_by_event(c_event, &replace_to,
3342 "c.type")))
3343 {
3344 replace_to = zbx_strdup(replace_to,
3345 zbx_dservice_type_string(atoi(replace_to)));
3346 }
3347 }
3348 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_PORT))
3349 {
3350 ret = DBget_dservice_value_by_event(c_event, &replace_to, "s.port");
3351 }
3352 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_STATUS))
3353 {
3354 if (SUCCEED == (ret = DBget_dservice_value_by_event(c_event, &replace_to,
3355 "s.status")))
3356 {
3357 replace_to = zbx_strdup(replace_to,
3358 zbx_dobject_status2str(atoi(replace_to)));
3359 }
3360 }
3361 else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_UPTIME))
3362 {
3363 zbx_snprintf(sql, sizeof(sql),
3364 "case when s.status=%d then s.lastup else s.lastdown end",
3365 DOBJECT_STATUS_UP);
3366 if (SUCCEED == (ret = DBget_dservice_value_by_event(c_event, &replace_to, sql)))
3367 {
3368 replace_to = zbx_strdup(replace_to,
3369 zbx_age2str(time(NULL) - atoi(replace_to)));
3370 }
3371 }
3372 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3373 {
3374 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3375 "r.proxy_hostid")))
3376 {
3377 zbx_uint64_t proxy_hostid;
3378
3379 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3380
3381 if (0 == proxy_hostid)
3382 replace_to = zbx_strdup(replace_to, "");
3383 else
3384 ret = DBget_host_value(proxy_hostid, &replace_to, "host");
3385 }
3386 }
3387 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3388 {
3389 if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3390 "r.proxy_hostid")))
3391 {
3392 zbx_uint64_t proxy_hostid;
3393
3394 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3395
3396 if (0 == proxy_hostid)
3397 {
3398 replace_to = zbx_strdup(replace_to, "");
3399 }
3400 else
3401 {
3402 ret = DBget_host_value(proxy_hostid, &replace_to,
3403 "description");
3404 }
3405 }
3406 }
3407 else if (0 == strcmp(m, MVAR_TIME))
3408 {
3409 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3410 }
3411 }
3412 else if (0 == indexed_macro && EVENT_SOURCE_AUTOREGISTRATION == c_event->source)
3413 {
3414 if (ZBX_TOKEN_USER_MACRO == token.type)
3415 {
3416 DCget_user_macro(NULL, 0, m, &replace_to);
3417 pos = token.loc.r;
3418 }
3419 else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3420 {
3421 ret = get_action_value(m, *actionid, &replace_to);
3422 }
3423 else if (0 == strcmp(m, MVAR_DATE))
3424 {
3425 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3426 }
3427 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3428 {
3429 get_event_value(m, event, &replace_to, userid);
3430 }
3431 else if (0 == strcmp(m, MVAR_HOST_METADATA))
3432 {
3433 ret = get_autoreg_value_by_event(c_event, &replace_to, "host_metadata");
3434 }
3435 else if (0 == strcmp(m, MVAR_HOST_HOST))
3436 {
3437 ret = get_autoreg_value_by_event(c_event, &replace_to, "host");
3438 }
3439 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3440 {
3441 ret = get_autoreg_value_by_event(c_event, &replace_to, "listen_ip");
3442 }
3443 else if (0 == strcmp(m, MVAR_HOST_PORT))
3444 {
3445 ret = get_autoreg_value_by_event(c_event, &replace_to, "listen_port");
3446 }
3447 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3448 {
3449 if (SUCCEED == (ret = get_autoreg_value_by_event(c_event, &replace_to,
3450 "proxy_hostid")))
3451 {
3452 zbx_uint64_t proxy_hostid;
3453
3454 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3455
3456 if (0 == proxy_hostid)
3457 replace_to = zbx_strdup(replace_to, "");
3458 else
3459 ret = DBget_host_value(proxy_hostid, &replace_to, "host");
3460 }
3461 }
3462 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3463 {
3464 if (SUCCEED == (ret = get_autoreg_value_by_event(c_event, &replace_to,
3465 "proxy_hostid")))
3466 {
3467 zbx_uint64_t proxy_hostid;
3468
3469 ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3470
3471 if (0 == proxy_hostid)
3472 {
3473 replace_to = zbx_strdup(replace_to, "");
3474 }
3475 else
3476 {
3477 ret = DBget_host_value(proxy_hostid, &replace_to,
3478 "description");
3479 }
3480 }
3481 }
3482 else if (0 == strcmp(m, MVAR_TIME))
3483 {
3484 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3485 }
3486 }
3487 else if (0 == indexed_macro && EVENT_SOURCE_INTERNAL == c_event->source &&
3488 EVENT_OBJECT_ITEM == c_event->object)
3489 {
3490 if (ZBX_TOKEN_USER_MACRO == token.type)
3491 {
3492 cache_item_hostid(&hostids, c_event->objectid);
3493 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3494 pos = token.loc.r;
3495 }
3496 else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3497 {
3498 ret = get_action_value(m, *actionid, &replace_to);
3499 }
3500 else if (0 == strcmp(m, MVAR_DATE))
3501 {
3502 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3503 }
3504 else if (0 == strcmp(m, MVAR_ESC_HISTORY))
3505 {
3506 get_escalation_history(*actionid, event, r_event, &replace_to, userid);
3507 }
3508 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3509 {
3510 if (NULL != r_event)
3511 get_recovery_event_value(m, r_event, &replace_to);
3512 }
3513 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3514 {
3515 get_current_event_value(m, c_event, &replace_to);
3516 }
3517 else if (0 == strcmp(m, MVAR_EVENT_NAME))
3518 {
3519 replace_to = zbx_strdup(replace_to, event->name);
3520 }
3521 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3522 {
3523 get_event_value(m, event, &replace_to, userid);
3524 }
3525 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3526 {
3527 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_HOST);
3528 }
3529 else if (0 == strcmp(m, MVAR_HOST_NAME))
3530 {
3531 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_NAME);
3532 }
3533 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3534 {
3535 ret = DBget_item_value(c_event->objectid, &replace_to,
3536 ZBX_REQUEST_HOST_DESCRIPTION);
3537 }
3538 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3539 {
3540 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_IP);
3541 }
3542 else if (0 == strcmp(m, MVAR_HOST_DNS))
3543 {
3544 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_DNS);
3545 }
3546 else if (0 == strcmp(m, MVAR_HOST_CONN))
3547 {
3548 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_CONN);
3549 }
3550 else if (0 == strcmp(m, MVAR_HOST_PORT))
3551 {
3552 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_PORT);
3553 }
3554 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3555 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3556 {
3557 ret = get_host_inventory_by_itemid(m, c_event->objectid, &replace_to);
3558 }
3559 else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3560 {
3561 ret = DBget_item_value(c_event->objectid, &replace_to,
3562 ZBX_REQUEST_ITEM_DESCRIPTION);
3563 }
3564 else if (0 == strcmp(m, MVAR_ITEM_ID))
3565 {
3566 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3567 }
3568 else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3569 {
3570 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_KEY);
3571 }
3572 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3573 {
3574 ret = DBget_item_value(c_event->objectid, &replace_to,
3575 ZBX_REQUEST_ITEM_KEY_ORIG);
3576 }
3577 else if (0 == strcmp(m, MVAR_ITEM_NAME))
3578 {
3579 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_NAME);
3580 }
3581 else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3582 {
3583 ret = DBget_item_value(c_event->objectid, &replace_to,
3584 ZBX_REQUEST_ITEM_NAME_ORIG);
3585 }
3586 else if (0 == strcmp(m, MVAR_ITEM_STATE))
3587 {
3588 replace_to = zbx_strdup(replace_to, zbx_item_state_string(c_event->value));
3589 }
3590 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3591 {
3592 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_PROXY_NAME);
3593 }
3594 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3595 {
3596 ret = DBget_item_value(c_event->objectid, &replace_to,
3597 ZBX_REQUEST_PROXY_DESCRIPTION);
3598 }
3599 else if (0 == strcmp(m, MVAR_TIME))
3600 {
3601 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3602 }
3603 }
3604 else if (0 == indexed_macro && EVENT_SOURCE_INTERNAL == c_event->source &&
3605 EVENT_OBJECT_LLDRULE == c_event->object)
3606 {
3607 if (ZBX_TOKEN_USER_MACRO == token.type)
3608 {
3609 cache_item_hostid(&hostids, c_event->objectid);
3610 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3611 pos = token.loc.r;
3612 }
3613 else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3614 {
3615 ret = get_action_value(m, *actionid, &replace_to);
3616 }
3617 else if (0 == strcmp(m, MVAR_DATE))
3618 {
3619 replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3620 }
3621 else if (0 == strcmp(m, MVAR_ESC_HISTORY))
3622 {
3623 get_escalation_history(*actionid, event, r_event, &replace_to, userid);
3624 }
3625 else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3626 {
3627 if (NULL != r_event)
3628 get_recovery_event_value(m, r_event, &replace_to);
3629 }
3630 else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3631 {
3632 get_current_event_value(m, c_event, &replace_to);
3633 }
3634 else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3635 {
3636 get_event_value(m, event, &replace_to, userid);
3637 }
3638 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3639 {
3640 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_HOST);
3641 }
3642 else if (0 == strcmp(m, MVAR_HOST_NAME))
3643 {
3644 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_NAME);
3645 }
3646 else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3647 {
3648 ret = DBget_item_value(c_event->objectid, &replace_to,
3649 ZBX_REQUEST_HOST_DESCRIPTION);
3650 }
3651 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3652 {
3653 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_IP);
3654 }
3655 else if (0 == strcmp(m, MVAR_HOST_DNS))
3656 {
3657 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_DNS);
3658 }
3659 else if (0 == strcmp(m, MVAR_HOST_CONN))
3660 {
3661 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_CONN);
3662 }
3663 else if (0 == strcmp(m, MVAR_HOST_PORT))
3664 {
3665 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_PORT);
3666 }
3667 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3668 0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3669 {
3670 ret = get_host_inventory_by_itemid(m, c_event->objectid, &replace_to);
3671 }
3672 else if (0 == strcmp(m, MVAR_LLDRULE_DESCRIPTION))
3673 {
3674 ret = DBget_item_value(c_event->objectid, &replace_to,
3675 ZBX_REQUEST_ITEM_DESCRIPTION);
3676 }
3677 else if (0 == strcmp(m, MVAR_LLDRULE_ID))
3678 {
3679 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3680 }
3681 else if (0 == strcmp(m, MVAR_LLDRULE_KEY))
3682 {
3683 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_KEY);
3684 }
3685 else if (0 == strcmp(m, MVAR_LLDRULE_KEY_ORIG))
3686 {
3687 ret = DBget_item_value(c_event->objectid, &replace_to,
3688 ZBX_REQUEST_ITEM_KEY_ORIG);
3689 }
3690 else if (0 == strcmp(m, MVAR_LLDRULE_NAME))
3691 {
3692 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_NAME);
3693 }
3694 else if (0 == strcmp(m, MVAR_LLDRULE_NAME_ORIG))
3695 {
3696 ret = DBget_item_value(c_event->objectid, &replace_to,
3697 ZBX_REQUEST_ITEM_NAME_ORIG);
3698 }
3699 else if (0 == strcmp(m, MVAR_LLDRULE_STATE))
3700 {
3701 replace_to = zbx_strdup(replace_to, zbx_item_state_string(c_event->value));
3702 }
3703 else if (0 == strcmp(m, MVAR_PROXY_NAME))
3704 {
3705 ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_PROXY_NAME);
3706 }
3707 else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3708 {
3709 ret = DBget_item_value(c_event->objectid, &replace_to,
3710 ZBX_REQUEST_PROXY_DESCRIPTION);
3711 }
3712 else if (0 == strcmp(m, MVAR_TIME))
3713 {
3714 replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3715 }
3716 }
3717 }
3718 else if (0 != (macro_type & (MACRO_TYPE_TRIGGER_DESCRIPTION | MACRO_TYPE_TRIGGER_COMMENTS)))
3719 {
3720 if (EVENT_OBJECT_TRIGGER == event->object)
3721 {
3722 if (ZBX_TOKEN_USER_MACRO == token.type)
3723 {
3724 cache_trigger_hostids(&hostids, event->trigger.expression,
3725 event->trigger.recovery_expression);
3726 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3727 pos = token.loc.r;
3728 }
3729 else if (ZBX_TOKEN_REFERENCE == token.type)
3730 {
3731 /* try to expand trigger expression if it hasn't been done yet */
3732 if (NULL == expression && NULL == (expression =
3733 get_expanded_expression(event->trigger.expression)))
3734 {
3735 /* expansion failed, reference substitution is impossible */
3736 token_search = ZBX_TOKEN_SEARCH_BASIC;
3737 continue;
3738 }
3739
3740 get_trigger_expression_constant(expression, &token.data.reference, &replace,
3741 &replace_len);
3742 }
3743 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3744 {
3745 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3746 ZBX_REQUEST_HOST_HOST);
3747 }
3748 else if (0 == strcmp(m, MVAR_HOST_NAME))
3749 {
3750 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3751 ZBX_REQUEST_HOST_NAME);
3752 }
3753 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3754 {
3755 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3756 ZBX_REQUEST_HOST_IP);
3757 }
3758 else if (0 == strcmp(m, MVAR_HOST_DNS))
3759 {
3760 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3761 ZBX_REQUEST_HOST_DNS);
3762 }
3763 else if (0 == strcmp(m, MVAR_HOST_CONN))
3764 {
3765 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3766 ZBX_REQUEST_HOST_CONN);
3767 }
3768 else if (0 == strcmp(m, MVAR_HOST_PORT))
3769 {
3770 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3771 ZBX_REQUEST_HOST_PORT);
3772 }
3773 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
3774 {
3775 ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid,
3776 event->clock, event->ns, raw_value);
3777 }
3778 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
3779 {
3780 ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid,
3781 raw_value);
3782 }
3783 }
3784 }
3785 else if (0 != (macro_type & MACRO_TYPE_TRIGGER_EXPRESSION))
3786 {
3787 if (EVENT_OBJECT_TRIGGER == event->object)
3788 {
3789 if (ZBX_TOKEN_USER_MACRO == token.type)
3790 {
3791 /* When processing trigger expressions the user macros are already expanded. */
3792 /* An unexpanded user macro means either unknown macro or macro value */
3793 /* validation failure. */
3794
3795 if (NULL != error)
3796 {
3797 zbx_snprintf(error, maxerrlen, "Invalid macro '%.*s' value",
3798 (int)(token.loc.r - token.loc.l + 1),
3799 *data + token.loc.l);
3800 }
3801
3802 res = FAIL;
3803 }
3804 else if (0 == strcmp(m, MVAR_TRIGGER_VALUE))
3805 replace_to = zbx_dsprintf(replace_to, "%d", event->value);
3806 }
3807 }
3808 else if (0 != (macro_type & MACRO_TYPE_TRIGGER_URL))
3809 {
3810 if (EVENT_OBJECT_TRIGGER == event->object)
3811 {
3812 if (ZBX_TOKEN_USER_MACRO == token.type)
3813 {
3814 cache_trigger_hostids(&hostids, event->trigger.expression,
3815 event->trigger.recovery_expression);
3816 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3817 pos = token.loc.r;
3818 }
3819 else if (0 == strcmp(m, MVAR_HOST_ID))
3820 {
3821 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3822 ZBX_REQUEST_HOST_ID);
3823 }
3824 else if (0 == strcmp(m, MVAR_HOST_HOST))
3825 {
3826 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3827 ZBX_REQUEST_HOST_HOST);
3828 }
3829 else if (0 == strcmp(m, MVAR_HOST_NAME))
3830 {
3831 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3832 ZBX_REQUEST_HOST_NAME);
3833 }
3834 else if (0 == strcmp(m, MVAR_HOST_IP))
3835 {
3836 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3837 ZBX_REQUEST_HOST_IP);
3838 }
3839 else if (0 == strcmp(m, MVAR_HOST_DNS))
3840 {
3841 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3842 ZBX_REQUEST_HOST_DNS);
3843 }
3844 else if (0 == strcmp(m, MVAR_HOST_CONN))
3845 {
3846 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3847 ZBX_REQUEST_HOST_CONN);
3848 }
3849 else if (0 == strcmp(m, MVAR_HOST_PORT))
3850 {
3851 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3852 ZBX_REQUEST_HOST_PORT);
3853 }
3854 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3855 {
3856 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
3857 }
3858 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
3859 {
3860 ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid,
3861 raw_value);
3862 }
3863 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
3864 {
3865 ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid,
3866 event->clock, event->ns, raw_value);
3867 }
3868 }
3869 }
3870 else if (0 == indexed_macro &&
3871 0 != (macro_type & (MACRO_TYPE_ITEM_KEY | MACRO_TYPE_PARAMS_FIELD |
3872 MACRO_TYPE_LLD_FILTER | MACRO_TYPE_ALLOWED_HOSTS)))
3873 {
3874 if (ZBX_TOKEN_USER_MACRO == token.type)
3875 {
3876 DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
3877 pos = token.loc.r;
3878 }
3879 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3880 replace_to = zbx_strdup(replace_to, dc_item->host.host);
3881 else if (0 == strcmp(m, MVAR_HOST_NAME))
3882 replace_to = zbx_strdup(replace_to, dc_item->host.name);
3883 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3884 {
3885 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
3886 {
3887 replace_to = zbx_strdup(replace_to, dc_item->interface.ip_orig);
3888 }
3889 else
3890 {
3891 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
3892 ZBX_REQUEST_HOST_IP);
3893 }
3894 }
3895 else if (0 == strcmp(m, MVAR_HOST_DNS))
3896 {
3897 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
3898 {
3899 replace_to = zbx_strdup(replace_to, dc_item->interface.dns_orig);
3900 }
3901 else
3902 {
3903 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
3904 ZBX_REQUEST_HOST_DNS);
3905 }
3906 }
3907 else if (0 == strcmp(m, MVAR_HOST_CONN))
3908 {
3909 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
3910 {
3911 replace_to = zbx_strdup(replace_to, dc_item->interface.addr);
3912 }
3913 else
3914 {
3915 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
3916 ZBX_REQUEST_HOST_CONN);
3917 }
3918 }
3919 }
3920 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_INTERFACE_ADDR))
3921 {
3922 if (ZBX_TOKEN_USER_MACRO == token.type)
3923 {
3924 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3925 pos = token.loc.r;
3926 }
3927 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3928 replace_to = zbx_strdup(replace_to, dc_host->host);
3929 else if (0 == strcmp(m, MVAR_HOST_NAME))
3930 replace_to = zbx_strdup(replace_to, dc_host->name);
3931 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3932 {
3933 if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
3934 dc_host->hostid, INTERFACE_TYPE_AGENT)))
3935 {
3936 replace_to = zbx_strdup(replace_to, interface.ip_orig);
3937 }
3938 }
3939 else if (0 == strcmp(m, MVAR_HOST_DNS))
3940 {
3941 if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
3942 dc_host->hostid, INTERFACE_TYPE_AGENT)))
3943 {
3944 replace_to = zbx_strdup(replace_to, interface.dns_orig);
3945 }
3946 }
3947 else if (0 == strcmp(m, MVAR_HOST_CONN))
3948 {
3949 if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
3950 dc_host->hostid, INTERFACE_TYPE_AGENT)))
3951 {
3952 replace_to = zbx_strdup(replace_to, interface.addr);
3953 }
3954 }
3955 }
3956 else if (0 != (macro_type & (MACRO_TYPE_COMMON | MACRO_TYPE_SNMP_OID)))
3957 {
3958 if (ZBX_TOKEN_USER_MACRO == token.type)
3959 {
3960 if (NULL != hostid)
3961 DCget_user_macro(hostid, 1, m, &replace_to);
3962 else
3963 DCget_user_macro(NULL, 0, m, &replace_to);
3964
3965 pos = token.loc.r;
3966 }
3967 }
3968 else if (0 != (macro_type & MACRO_TYPE_ITEM_EXPRESSION))
3969 {
3970 if (ZBX_TOKEN_USER_MACRO == token.type)
3971 {
3972 require_numeric = 1;
3973 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3974 pos = token.loc.r;
3975 }
3976 }
3977 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_SCRIPT))
3978 {
3979 if (ZBX_TOKEN_USER_MACRO == token.type)
3980 {
3981 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3982 pos = token.loc.r;
3983 }
3984 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3985 replace_to = zbx_strdup(replace_to, dc_host->host);
3986 else if (0 == strcmp(m, MVAR_HOST_NAME))
3987 replace_to = zbx_strdup(replace_to, dc_host->name);
3988 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3989 {
3990 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
3991 replace_to = zbx_strdup(replace_to, interface.ip_orig);
3992 require_address = 1;
3993 }
3994 else if (0 == strcmp(m, MVAR_HOST_DNS))
3995 {
3996 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
3997 replace_to = zbx_strdup(replace_to, interface.dns_orig);
3998 require_address = 1;
3999 }
4000 else if (0 == strcmp(m, MVAR_HOST_CONN))
4001 {
4002 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4003 replace_to = zbx_strdup(replace_to, interface.addr);
4004 require_address = 1;
4005 }
4006 }
4007 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_HTTPTEST_FIELD))
4008 {
4009 if (ZBX_TOKEN_USER_MACRO == token.type)
4010 {
4011 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4012 pos = token.loc.r;
4013 }
4014 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4015 replace_to = zbx_strdup(replace_to, dc_host->host);
4016 else if (0 == strcmp(m, MVAR_HOST_NAME))
4017 replace_to = zbx_strdup(replace_to, dc_host->name);
4018 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4019 {
4020 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4021 replace_to = zbx_strdup(replace_to, interface.ip_orig);
4022 }
4023 else if (0 == strcmp(m, MVAR_HOST_DNS))
4024 {
4025 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4026 replace_to = zbx_strdup(replace_to, interface.dns_orig);
4027 }
4028 else if (0 == strcmp(m, MVAR_HOST_CONN))
4029 {
4030 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4031 replace_to = zbx_strdup(replace_to, interface.addr);
4032 }
4033 }
4034 else if (0 == indexed_macro && (0 != (macro_type & (MACRO_TYPE_HTTP_RAW | MACRO_TYPE_HTTP_JSON |
4035 MACRO_TYPE_HTTP_XML))))
4036 {
4037 if (ZBX_TOKEN_USER_MACRO == token.type)
4038 {
4039 DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4040 pos = token.loc.r;
4041 }
4042 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4043 {
4044 replace_to = zbx_strdup(replace_to, dc_host->host);
4045 }
4046 else if (0 == strcmp(m, MVAR_HOST_NAME))
4047 {
4048 replace_to = zbx_strdup(replace_to, dc_host->name);
4049 }
4050 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4051 {
4052 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4053 replace_to = zbx_strdup(replace_to, interface.ip_orig);
4054 }
4055 else if (0 == strcmp(m, MVAR_HOST_DNS))
4056 {
4057 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4058 replace_to = zbx_strdup(replace_to, interface.dns_orig);
4059 }
4060 else if (0 == strcmp(m, MVAR_HOST_CONN))
4061 {
4062 if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4063 replace_to = zbx_strdup(replace_to, interface.addr);
4064 }
4065 else if (0 == strcmp(m, MVAR_ITEM_ID))
4066 {
4067 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, dc_item->itemid);
4068 }
4069 else if (0 == strcmp(m, MVAR_ITEM_KEY))
4070 {
4071 replace_to = zbx_strdup(replace_to, dc_item->key);
4072 }
4073 else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
4074 {
4075 replace_to = zbx_strdup(replace_to, dc_item->key_orig);
4076 }
4077 }
4078 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_ALERT))
4079 {
4080 if (0 == strcmp(m, MVAR_ALERT_SENDTO))
4081 replace_to = zbx_strdup(replace_to, alert->sendto);
4082 else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
4083 replace_to = zbx_strdup(replace_to, alert->subject);
4084 else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
4085 replace_to = zbx_strdup(replace_to, alert->message);
4086 }
4087 else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_JMX_ENDPOINT))
4088 {
4089 if (ZBX_TOKEN_USER_MACRO == token.type)
4090 {
4091 DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
4092 pos = token.loc.r;
4093 }
4094 else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4095 replace_to = zbx_strdup(replace_to, dc_item->host.host);
4096 else if (0 == strcmp(m, MVAR_HOST_NAME))
4097 replace_to = zbx_strdup(replace_to, dc_item->host.name);
4098 else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4099 {
4100 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4101 {
4102 replace_to = zbx_strdup(replace_to, dc_item->interface.ip_orig);
4103 }
4104 else
4105 {
4106 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4107 ZBX_REQUEST_HOST_IP);
4108 }
4109 }
4110 else if (0 == strcmp(m, MVAR_HOST_DNS))
4111 {
4112 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4113 {
4114 replace_to = zbx_strdup(replace_to, dc_item->interface.dns_orig);
4115 }
4116 else
4117 {
4118 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4119 ZBX_REQUEST_HOST_DNS);
4120 }
4121 }
4122 else if (0 == strcmp(m, MVAR_HOST_CONN))
4123 {
4124 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4125 {
4126 replace_to = zbx_strdup(replace_to, dc_item->interface.addr);
4127 }
4128 else
4129 {
4130 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4131 ZBX_REQUEST_HOST_CONN);
4132 }
4133 }
4134 else if (0 == strcmp(m, MVAR_HOST_PORT))
4135 {
4136 if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4137 {
4138 replace_to = zbx_dsprintf(replace_to, "%u", dc_item->interface.port);
4139 }
4140 else
4141 {
4142 ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4143 ZBX_REQUEST_HOST_PORT);
4144 }
4145 }
4146 }
4147 else if (macro_type & MACRO_TYPE_TRIGGER_TAG)
4148 {
4149 if (EVENT_SOURCE_TRIGGERS == event->source)
4150 {
4151 if (ZBX_TOKEN_USER_MACRO == token.type)
4152 {
4153 cache_trigger_hostids(&hostids, event->trigger.expression,
4154 event->trigger.recovery_expression);
4155 DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
4156 pos = token.loc.r;
4157 }
4158 else if (0 == strcmp(m, MVAR_HOST_ID))
4159 {
4160 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4161 ZBX_REQUEST_HOST_ID);
4162 }
4163 else if (0 == strcmp(m, MVAR_HOST_HOST))
4164 {
4165 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4166 ZBX_REQUEST_HOST_HOST);
4167 }
4168 else if (0 == strcmp(m, MVAR_HOST_NAME))
4169 {
4170 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4171 ZBX_REQUEST_HOST_NAME);
4172 }
4173 else if (0 == strcmp(m, MVAR_HOST_IP))
4174 {
4175 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4176 ZBX_REQUEST_HOST_IP);
4177 }
4178 else if (0 == strcmp(m, MVAR_HOST_DNS))
4179 {
4180 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4181 ZBX_REQUEST_HOST_DNS);
4182 }
4183 else if (0 == strcmp(m, MVAR_HOST_CONN))
4184 {
4185 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4186 ZBX_REQUEST_HOST_CONN);
4187 }
4188 else if (0 == strcmp(m, MVAR_HOST_PORT))
4189 {
4190 ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4191 ZBX_REQUEST_HOST_PORT);
4192 }
4193 else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
4194 {
4195 ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid,
4196 raw_value);
4197 }
4198 else if (0 == strcmp(m, MVAR_ITEM_VALUE))
4199 {
4200 ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid,
4201 event->clock, event->ns, raw_value);
4202 }
4203 else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)))
4204 {
4205 ret = get_host_inventory(m, event->trigger.expression, &replace_to,
4206 N_functionid);
4207 }
4208 else if (0 == strcmp(m, MVAR_TRIGGER_ID))
4209 {
4210 replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
4211 }
4212 }
4213 }
4214
4215 if (0 != (macro_type & MACRO_TYPE_HTTP_JSON) && NULL != replace_to)
4216 zbx_json_escape(&replace_to);
4217
4218 if (0 != (macro_type & MACRO_TYPE_HTTP_XML) && NULL != replace_to)
4219 {
4220 char *replace_to_esc;
4221
4222 replace_to_esc = xml_escape_dyn(replace_to);
4223 zbx_free(replace_to);
4224 replace_to = replace_to_esc;
4225 }
4226
4227 if (ZBX_TOKEN_FUNC_MACRO == token.type && NULL != replace_to)
4228 {
4229 if (SUCCEED != (ret = zbx_calculate_macro_function(*data, &token.data.func_macro, &replace_to)))
4230 zbx_free(replace_to);
4231 }
4232
4233 if (NULL != replace_to)
4234 {
4235 if (1 == require_numeric)
4236 {
4237 if (SUCCEED == (res = is_double_suffix(replace_to, ZBX_FLAG_DOUBLE_SUFFIX)))
4238 {
4239 wrap_negative_double_suffix(&replace_to, NULL);
4240 }
4241 else if (NULL != error)
4242 {
4243 zbx_snprintf(error, maxerrlen, "Macro '%.*s' value is not numeric",
4244 (int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4245 }
4246 }
4247 else if (1 == require_address && NULL != strstr(replace_to, "{$"))
4248 {
4249 /* Macros should be already expanded. An unexpanded user macro means either unknown */
4250 /* macro or macro value validation failure. */
4251 zbx_snprintf(error, maxerrlen, "Invalid macro '%.*s' value",
4252 (int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4253 res = FAIL;
4254 }
4255 }
4256
4257 if (FAIL == ret)
4258 {
4259 zabbix_log(LOG_LEVEL_DEBUG, "cannot resolve macro '%.*s'",
4260 (int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4261 replace_to = zbx_strdup(replace_to, STR_UNKNOWN_VARIABLE);
4262 }
4263
4264 if (ZBX_TOKEN_USER_MACRO == token.type || (ZBX_TOKEN_MACRO == token.type && 0 == indexed_macro))
4265 (*data)[token.loc.r + 1] = c;
4266
4267 if (NULL != replace_to)
4268 {
4269 pos = token.loc.r;
4270
4271 pos += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token.loc.l,
4272 token.loc.r - token.loc.l + 1, replace_to, strlen(replace_to));
4273 zbx_free(replace_to);
4274 }
4275 else if (NULL != replace)
4276 {
4277 pos = token.loc.r;
4278
4279 pos += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token.loc.l,
4280 token.loc.r - token.loc.l + 1, replace, replace_len);
4281
4282 replace = NULL;
4283 }
4284
4285 pos++;
4286 }
4287
4288 zbx_free(expression);
4289 zbx_vector_uint64_destroy(&hostids);
4290
4291 zabbix_log(LOG_LEVEL_DEBUG, "End %s() data:'%s'", __function_name, *data);
4292
4293 return res;
4294 }
4295
extract_expression_functionids(zbx_vector_uint64_t * functionids,const char * expression)4296 static int extract_expression_functionids(zbx_vector_uint64_t *functionids, const char *expression)
4297 {
4298 const char *bl, *br;
4299 zbx_uint64_t functionid;
4300
4301 for (bl = strchr(expression, '{'); NULL != bl; bl = strchr(bl, '{'))
4302 {
4303 if (NULL == (br = strchr(bl, '}')))
4304 break;
4305
4306 if (SUCCEED != is_uint64_n(bl + 1, br - bl - 1, &functionid))
4307 break;
4308
4309 zbx_vector_uint64_append(functionids, functionid);
4310
4311 bl = br + 1;
4312 }
4313
4314 return (NULL == bl ? SUCCEED : FAIL);
4315 }
4316
zbx_extract_functionids(zbx_vector_uint64_t * functionids,zbx_vector_ptr_t * triggers)4317 static void zbx_extract_functionids(zbx_vector_uint64_t *functionids, zbx_vector_ptr_t *triggers)
4318 {
4319 const char *__function_name = "zbx_extract_functionids";
4320
4321 DC_TRIGGER *tr;
4322 int i, values_num_save;
4323
4324 zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __function_name, triggers->values_num);
4325
4326 for (i = 0; i < triggers->values_num; i++)
4327 {
4328 const char *error_expression = NULL;
4329
4330 tr = (DC_TRIGGER *)triggers->values[i];
4331
4332 if (NULL != tr->new_error)
4333 continue;
4334
4335 values_num_save = functionids->values_num;
4336
4337 if (SUCCEED != extract_expression_functionids(functionids, tr->expression))
4338 {
4339 error_expression = tr->expression;
4340 }
4341 else if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode &&
4342 SUCCEED != extract_expression_functionids(functionids, tr->recovery_expression))
4343 {
4344 error_expression = tr->recovery_expression;
4345 }
4346
4347 if (NULL != error_expression)
4348 {
4349 tr->new_error = zbx_dsprintf(tr->new_error, "Invalid expression [%s]", error_expression);
4350 tr->new_value = TRIGGER_VALUE_UNKNOWN;
4351 functionids->values_num = values_num_save;
4352 }
4353 }
4354
4355 zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4356 zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4357
4358 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() functionids_num:%d", __function_name, functionids->values_num);
4359 }
4360
4361 typedef struct
4362 {
4363 DC_TRIGGER *trigger;
4364 int start_index;
4365 int count;
4366 }
4367 zbx_trigger_func_position_t;
4368
4369 /******************************************************************************
4370 * *
4371 * Function: expand_trigger_macros *
4372 * *
4373 * Purpose: expand macros in a trigger expression *
4374 * *
4375 * Parameters: event - The trigger event structure *
4376 * trigger - The trigger where to expand macros in *
4377 * *
4378 * Author: Andrea Biscuola *
4379 * *
4380 ******************************************************************************/
expand_trigger_macros(DB_EVENT * event,DC_TRIGGER * trigger,char * error,size_t maxerrlen)4381 static int expand_trigger_macros(DB_EVENT *event, DC_TRIGGER *trigger, char *error, size_t maxerrlen)
4382 {
4383 if (FAIL == substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4384 &trigger->expression, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen))
4385 {
4386 return FAIL;
4387 }
4388
4389 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode)
4390 {
4391 if (FAIL == substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4392 &trigger->recovery_expression, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen))
4393 {
4394 return FAIL;
4395 }
4396 }
4397
4398 return SUCCEED;
4399 }
4400
4401 /******************************************************************************
4402 * *
4403 * Function: zbx_link_triggers_with_functions *
4404 * *
4405 * Purpose: triggers links with functions *
4406 * *
4407 * Parameters: triggers_func_pos - [IN/OUT] pointer to the list of triggers *
4408 * with functions position in functionids *
4409 * array *
4410 * functionids - [IN/OUT] array of function IDs *
4411 * trigger_order - [IN] array of triggers *
4412 * *
4413 ******************************************************************************/
zbx_link_triggers_with_functions(zbx_vector_ptr_t * triggers_func_pos,zbx_vector_uint64_t * functionids,zbx_vector_ptr_t * trigger_order)4414 static void zbx_link_triggers_with_functions(zbx_vector_ptr_t *triggers_func_pos, zbx_vector_uint64_t *functionids,
4415 zbx_vector_ptr_t *trigger_order)
4416 {
4417 const char *__function_name = "zbx_link_triggers_with_functions";
4418
4419 zbx_vector_uint64_t funcids;
4420 DC_TRIGGER *tr;
4421 DB_EVENT ev;
4422 int i;
4423
4424 zabbix_log(LOG_LEVEL_DEBUG, "In %s() trigger_order_num:%d", __function_name, trigger_order->values_num);
4425
4426 zbx_vector_uint64_create(&funcids);
4427 zbx_vector_uint64_reserve(&funcids, functionids->values_num);
4428
4429 ev.object = EVENT_OBJECT_TRIGGER;
4430
4431 for (i = 0; i < trigger_order->values_num; i++)
4432 {
4433 zbx_trigger_func_position_t *tr_func_pos;
4434
4435 tr = (DC_TRIGGER *)trigger_order->values[i];
4436
4437 if (NULL != tr->new_error)
4438 continue;
4439
4440 ev.value = tr->value;
4441
4442 expand_trigger_macros(&ev, tr, NULL, 0);
4443
4444 if (SUCCEED == extract_expression_functionids(&funcids, tr->expression))
4445 {
4446 tr_func_pos = (zbx_trigger_func_position_t *)zbx_malloc(NULL, sizeof(zbx_trigger_func_position_t));
4447 tr_func_pos->trigger = tr;
4448 tr_func_pos->start_index = functionids->values_num;
4449 tr_func_pos->count = funcids.values_num;
4450
4451 zbx_vector_uint64_append_array(functionids, funcids.values, funcids.values_num);
4452 zbx_vector_ptr_append(triggers_func_pos, tr_func_pos);
4453 }
4454
4455 zbx_vector_uint64_clear(&funcids);
4456 }
4457
4458 zbx_vector_uint64_destroy(&funcids);
4459
4460 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() triggers_func_pos_num:%d", __function_name,
4461 triggers_func_pos->values_num);
4462 }
4463
4464 /******************************************************************************
4465 * *
4466 * Function: zbx_determine_items_in_expressions *
4467 * *
4468 * Purpose: mark triggers that use one of the items in problem expression *
4469 * with ZBX_DC_TRIGGER_PROBLEM_EXPRESSION flag *
4470 * *
4471 * Parameters: trigger_order - [IN/OUT] pointer to the list of triggers *
4472 * itemids - [IN] array of item IDs *
4473 * item_num - [IN] number of items *
4474 * *
4475 ******************************************************************************/
zbx_determine_items_in_expressions(zbx_vector_ptr_t * trigger_order,const zbx_uint64_t * itemids,int item_num)4476 void zbx_determine_items_in_expressions(zbx_vector_ptr_t *trigger_order, const zbx_uint64_t *itemids, int item_num)
4477 {
4478 zbx_vector_ptr_t triggers_func_pos;
4479 zbx_vector_uint64_t functionids, itemids_sorted;
4480 DC_FUNCTION *functions = NULL;
4481 int *errcodes = NULL, t, f;
4482
4483 zbx_vector_uint64_create(&itemids_sorted);
4484 zbx_vector_uint64_append_array(&itemids_sorted, itemids, item_num);
4485 zbx_vector_uint64_sort(&itemids_sorted, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4486
4487 zbx_vector_ptr_create(&triggers_func_pos);
4488 zbx_vector_ptr_reserve(&triggers_func_pos, trigger_order->values_num);
4489
4490 zbx_vector_uint64_create(&functionids);
4491 zbx_vector_uint64_reserve(&functionids, item_num);
4492
4493 zbx_link_triggers_with_functions(&triggers_func_pos, &functionids, trigger_order);
4494
4495 functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids.values_num);
4496 errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids.values_num);
4497
4498 DCconfig_get_functions_by_functionids(functions, functionids.values, errcodes, functionids.values_num);
4499
4500 for (t = 0; t < triggers_func_pos.values_num; t++)
4501 {
4502 zbx_trigger_func_position_t *func_pos = (zbx_trigger_func_position_t *)triggers_func_pos.values[t];
4503
4504 for (f = func_pos->start_index; f < func_pos->start_index + func_pos->count; f++)
4505 {
4506 if (FAIL != zbx_vector_uint64_bsearch(&itemids_sorted, functions[f].itemid,
4507 ZBX_DEFAULT_UINT64_COMPARE_FUNC))
4508 {
4509 func_pos->trigger->flags |= ZBX_DC_TRIGGER_PROBLEM_EXPRESSION;
4510 break;
4511 }
4512 }
4513 }
4514
4515 DCconfig_clean_functions(functions, errcodes, functionids.values_num);
4516 zbx_free(errcodes);
4517 zbx_free(functions);
4518
4519 zbx_vector_ptr_clear_ext(&triggers_func_pos, zbx_ptr_free);
4520 zbx_vector_ptr_destroy(&triggers_func_pos);
4521
4522 zbx_vector_uint64_clear(&functionids);
4523 zbx_vector_uint64_destroy(&functionids);
4524
4525 zbx_vector_uint64_clear(&itemids_sorted);
4526 zbx_vector_uint64_destroy(&itemids_sorted);
4527 }
4528
4529 typedef struct
4530 {
4531 /* input data */
4532 zbx_uint64_t itemid;
4533 char *function;
4534 char *parameter;
4535 zbx_timespec_t timespec;
4536
4537 /* output data */
4538 char *value;
4539 char *error;
4540 }
4541 zbx_func_t;
4542
4543 typedef struct
4544 {
4545 zbx_uint64_t functionid;
4546 zbx_func_t *func;
4547 }
4548 zbx_ifunc_t;
4549
func_hash_func(const void * data)4550 static zbx_hash_t func_hash_func(const void *data)
4551 {
4552 const zbx_func_t *func = (const zbx_func_t *)data;
4553 zbx_hash_t hash;
4554
4555 hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&func->itemid);
4556 hash = ZBX_DEFAULT_STRING_HASH_ALGO(func->function, strlen(func->function), hash);
4557 hash = ZBX_DEFAULT_STRING_HASH_ALGO(func->parameter, strlen(func->parameter), hash);
4558 hash = ZBX_DEFAULT_HASH_ALGO(&func->timespec.sec, sizeof(func->timespec.sec), hash);
4559 hash = ZBX_DEFAULT_HASH_ALGO(&func->timespec.ns, sizeof(func->timespec.ns), hash);
4560
4561 return hash;
4562 }
4563
func_compare_func(const void * d1,const void * d2)4564 static int func_compare_func(const void *d1, const void *d2)
4565 {
4566 const zbx_func_t *func1 = (const zbx_func_t *)d1;
4567 const zbx_func_t *func2 = (const zbx_func_t *)d2;
4568 int ret;
4569
4570 ZBX_RETURN_IF_NOT_EQUAL(func1->itemid, func2->itemid);
4571
4572 if (0 != (ret = strcmp(func1->function, func2->function)))
4573 return ret;
4574
4575 if (0 != (ret = strcmp(func1->parameter, func2->parameter)))
4576 return ret;
4577
4578 ZBX_RETURN_IF_NOT_EQUAL(func1->timespec.sec, func2->timespec.sec);
4579 ZBX_RETURN_IF_NOT_EQUAL(func1->timespec.ns, func2->timespec.ns);
4580
4581 return 0;
4582 }
4583
func_clean(void * ptr)4584 static void func_clean(void *ptr)
4585 {
4586 zbx_func_t *func = (zbx_func_t *)ptr;
4587
4588 zbx_free(func->function);
4589 zbx_free(func->parameter);
4590 zbx_free(func->value);
4591 zbx_free(func->error);
4592 }
4593
4594 /******************************************************************************
4595 * *
4596 * Function: zbx_populate_function_items *
4597 * *
4598 * Purpose: prepare hashset of functions to evaluate *
4599 * *
4600 * Parameters: functionids - [IN] function identifiers *
4601 * funcs - [OUT] functions indexed by itemid, name, *
4602 * parameter, timestamp *
4603 * ifuncs - [OUT] function index by functionid *
4604 * trigger - [IN] vector of triggers, sorted by triggerid *
4605 * *
4606 ******************************************************************************/
zbx_populate_function_items(const zbx_vector_uint64_t * functionids,zbx_hashset_t * funcs,zbx_hashset_t * ifuncs,const zbx_vector_ptr_t * triggers)4607 static void zbx_populate_function_items(const zbx_vector_uint64_t *functionids, zbx_hashset_t *funcs,
4608 zbx_hashset_t *ifuncs, const zbx_vector_ptr_t *triggers)
4609 {
4610 const char *__function_name = "zbx_populate_function_items";
4611
4612 int i, j;
4613 DC_TRIGGER *tr;
4614 DC_FUNCTION *functions = NULL;
4615 int *errcodes = NULL;
4616 zbx_ifunc_t ifunc_local;
4617 zbx_func_t *func, func_local;
4618
4619 zabbix_log(LOG_LEVEL_DEBUG, "In %s() functionids_num:%d", __function_name, functionids->values_num);
4620
4621 func_local.value = NULL;
4622 func_local.error = NULL;
4623
4624 functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids->values_num);
4625 errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids->values_num);
4626
4627 DCconfig_get_functions_by_functionids(functions, functionids->values, errcodes, functionids->values_num);
4628
4629 for (i = 0; i < functionids->values_num; i++)
4630 {
4631 if (SUCCEED != errcodes[i])
4632 continue;
4633
4634 func_local.itemid = functions[i].itemid;
4635
4636 if (FAIL != (j = zbx_vector_ptr_bsearch(triggers, &functions[i].triggerid,
4637 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4638 {
4639 tr = (DC_TRIGGER *)triggers->values[j];
4640 func_local.timespec = tr->timespec;
4641 }
4642 else
4643 {
4644 func_local.timespec.sec = 0;
4645 func_local.timespec.ns = 0;
4646 }
4647
4648 func_local.function = functions[i].function;
4649 func_local.parameter = functions[i].parameter;
4650
4651 if (NULL == (func = (zbx_func_t *)zbx_hashset_search(funcs, &func_local)))
4652 {
4653 func = (zbx_func_t *)zbx_hashset_insert(funcs, &func_local, sizeof(func_local));
4654 func->function = zbx_strdup(NULL, func_local.function);
4655 func->parameter = zbx_strdup(NULL, func_local.parameter);
4656 }
4657
4658 ifunc_local.functionid = functions[i].functionid;
4659 ifunc_local.func = func;
4660 zbx_hashset_insert(ifuncs, &ifunc_local, sizeof(ifunc_local));
4661 }
4662
4663 DCconfig_clean_functions(functions, errcodes, functionids->values_num);
4664
4665 zbx_free(errcodes);
4666 zbx_free(functions);
4667
4668 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() ifuncs_num:%d", __function_name, ifuncs->num_data);
4669 }
4670
zbx_evaluate_item_functions(zbx_hashset_t * funcs,zbx_vector_ptr_t * unknown_msgs)4671 static void zbx_evaluate_item_functions(zbx_hashset_t *funcs, zbx_vector_ptr_t *unknown_msgs)
4672 {
4673 const char *__function_name = "zbx_evaluate_item_functions";
4674
4675 DC_ITEM *items = NULL;
4676 char value[MAX_BUFFER_LEN], *error = NULL;
4677 int i;
4678 zbx_func_t *func;
4679 zbx_vector_uint64_t itemids;
4680 int *errcodes = NULL;
4681 zbx_hashset_iter_t iter;
4682
4683 zabbix_log(LOG_LEVEL_DEBUG, "In %s() funcs_num:%d", __function_name, funcs->num_data);
4684
4685 zbx_vector_uint64_create(&itemids);
4686 zbx_vector_uint64_reserve(&itemids, funcs->num_data);
4687
4688 zbx_hashset_iter_reset(funcs, &iter);
4689 while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter)))
4690 zbx_vector_uint64_append(&itemids, func->itemid);
4691
4692 zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4693 zbx_vector_uint64_uniq(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4694
4695 items = (DC_ITEM *)zbx_malloc(items, sizeof(DC_ITEM) * (size_t)itemids.values_num);
4696 errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * (size_t)itemids.values_num);
4697
4698 DCconfig_get_items_by_itemids(items, itemids.values, errcodes, itemids.values_num);
4699
4700 zbx_hashset_iter_reset(funcs, &iter);
4701 while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter)))
4702 {
4703 int ret_unknown = 0; /* flag raised if current function evaluates to ZBX_UNKNOWN */
4704 char *unknown_msg;
4705
4706 i = zbx_vector_uint64_bsearch(&itemids, func->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4707
4708 if (SUCCEED != errcodes[i])
4709 {
4710 func->error = zbx_dsprintf(func->error, "Cannot evaluate function \"%s(%s)\":"
4711 " item does not exist.",
4712 func->function, func->parameter);
4713 continue;
4714 }
4715
4716 /* do not evaluate if the item is disabled or belongs to a disabled host */
4717
4718 if (ITEM_STATUS_ACTIVE != items[i].status)
4719 {
4720 func->error = zbx_dsprintf(func->error, "Cannot evaluate function \"%s:%s.%s(%s)\":"
4721 " item is disabled.",
4722 items[i].host.host, items[i].key_orig, func->function, func->parameter);
4723 continue;
4724 }
4725
4726 if (HOST_STATUS_MONITORED != items[i].host.status)
4727 {
4728 func->error = zbx_dsprintf(func->error, "Cannot evaluate function \"%s:%s.%s(%s)\":"
4729 " item belongs to a disabled host.",
4730 items[i].host.host, items[i].key_orig, func->function, func->parameter);
4731 continue;
4732 }
4733
4734 /* If the item is NOTSUPPORTED then evaluation is allowed for: */
4735 /* - time-based functions and nodata(). Their values can be */
4736 /* evaluated to regular numbers even for NOTSUPPORTED items. */
4737 /* - other functions. Result of evaluation is ZBX_UNKNOWN. */
4738
4739 if (ITEM_STATE_NOTSUPPORTED == items[i].state && FAIL == evaluatable_for_notsupported(func->function))
4740 {
4741 /* compose and store 'unknown' message for future use */
4742 unknown_msg = zbx_dsprintf(NULL,
4743 "Cannot evaluate function \"%s:%s.%s(%s)\": item is not supported.",
4744 items[i].host.host, items[i].key_orig, func->function, func->parameter);
4745
4746 zbx_free(func->error);
4747 zbx_vector_ptr_append(unknown_msgs, unknown_msg);
4748 ret_unknown = 1;
4749 }
4750
4751 if (0 == ret_unknown && SUCCEED != evaluate_function(value, &items[i], func->function,
4752 func->parameter, &func->timespec, &error))
4753 {
4754 /* compose and store error message for future use */
4755 if (NULL != error)
4756 {
4757 unknown_msg = zbx_dsprintf(NULL,
4758 "Cannot evaluate function \"%s:%s.%s(%s)\": %s.",
4759 items[i].host.host, items[i].key_orig, func->function,
4760 func->parameter, error);
4761
4762 zbx_free(func->error);
4763 zbx_free(error);
4764 }
4765 else
4766 {
4767 unknown_msg = zbx_dsprintf(NULL,
4768 "Cannot evaluate function \"%s:%s.%s(%s)\".",
4769 items[i].host.host, items[i].key_orig,
4770 func->function, func->parameter);
4771
4772 zbx_free(func->error);
4773 }
4774
4775 zbx_vector_ptr_append(unknown_msgs, unknown_msg);
4776 ret_unknown = 1;
4777 }
4778
4779 if (0 == ret_unknown)
4780 {
4781 func->value = zbx_strdup(func->value, value);
4782 }
4783 else
4784 {
4785 /* write a special token of unknown value with 'unknown' message number, like */
4786 /* ZBX_UNKNOWN0, ZBX_UNKNOWN1 etc. not wrapped in () */
4787 func->value = zbx_dsprintf(func->value, ZBX_UNKNOWN_STR "%d",
4788 unknown_msgs->values_num - 1);
4789 }
4790 }
4791
4792 DCconfig_clean_items(items, errcodes, itemids.values_num);
4793 zbx_vector_uint64_destroy(&itemids);
4794
4795 zbx_free(errcodes);
4796 zbx_free(items);
4797
4798 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4799 }
4800
substitute_expression_functions_results(zbx_hashset_t * ifuncs,char * expression,char ** out,size_t * out_alloc,char ** error)4801 static int substitute_expression_functions_results(zbx_hashset_t *ifuncs, char *expression, char **out,
4802 size_t *out_alloc, char **error)
4803 {
4804 char *br, *bl;
4805 size_t out_offset = 0;
4806 zbx_uint64_t functionid;
4807 zbx_func_t *func;
4808 zbx_ifunc_t *ifunc;
4809
4810 for (br = expression, bl = strchr(expression, '{'); NULL != bl; bl = strchr(bl, '{'))
4811 {
4812 *bl = '\0';
4813 zbx_strcpy_alloc(out, out_alloc, &out_offset, br);
4814 *bl = '{';
4815
4816 if (NULL == (br = strchr(bl, '}')))
4817 {
4818 *error = zbx_strdup(*error, "Invalid trigger expression");
4819 return FAIL;
4820 }
4821
4822 *br = '\0';
4823
4824 ZBX_STR2UINT64(functionid, bl + 1);
4825
4826 *br++ = '}';
4827 bl = br;
4828
4829 if (NULL == (ifunc = (zbx_ifunc_t *)zbx_hashset_search(ifuncs, &functionid)))
4830 {
4831 *error = zbx_dsprintf(*error, "Cannot obtain function"
4832 " and item for functionid: " ZBX_FS_UI64, functionid);
4833 return FAIL;
4834 }
4835
4836 func = ifunc->func;
4837
4838 if (NULL != func->error)
4839 {
4840 *error = zbx_strdup(*error, func->error);
4841 return FAIL;
4842 }
4843
4844 if (NULL == func->value)
4845 {
4846 *error = zbx_strdup(*error, "Unexpected error while processing a trigger expression");
4847 return FAIL;
4848 }
4849
4850 if (SUCCEED != is_double_suffix(func->value, ZBX_FLAG_DOUBLE_SUFFIX) || '-' == *func->value)
4851 {
4852 zbx_chrcpy_alloc(out, out_alloc, &out_offset, '(');
4853 zbx_strcpy_alloc(out, out_alloc, &out_offset, func->value);
4854 zbx_chrcpy_alloc(out, out_alloc, &out_offset, ')');
4855 }
4856 else
4857 zbx_strcpy_alloc(out, out_alloc, &out_offset, func->value);
4858 }
4859
4860 zbx_strcpy_alloc(out, out_alloc, &out_offset, br);
4861
4862 return SUCCEED;
4863 }
4864
zbx_substitute_functions_results(zbx_hashset_t * ifuncs,zbx_vector_ptr_t * triggers)4865 static void zbx_substitute_functions_results(zbx_hashset_t *ifuncs, zbx_vector_ptr_t *triggers)
4866 {
4867 const char *__function_name = "zbx_substitute_functions_results";
4868
4869 DC_TRIGGER *tr;
4870 char *out = NULL;
4871 size_t out_alloc = TRIGGER_EXPRESSION_LEN_MAX;
4872 int i;
4873
4874 zabbix_log(LOG_LEVEL_DEBUG, "In %s() ifuncs_num:%d tr_num:%d",
4875 __function_name, ifuncs->num_data, triggers->values_num);
4876
4877 out = (char *)zbx_malloc(out, out_alloc);
4878
4879 for (i = 0; i < triggers->values_num; i++)
4880 {
4881 tr = (DC_TRIGGER *)triggers->values[i];
4882
4883 if (NULL != tr->new_error)
4884 continue;
4885
4886 if( SUCCEED != substitute_expression_functions_results(ifuncs, tr->expression, &out, &out_alloc,
4887 &tr->new_error))
4888 {
4889 tr->new_value = TRIGGER_VALUE_UNKNOWN;
4890 continue;
4891 }
4892
4893 zabbix_log(LOG_LEVEL_DEBUG, "%s() expression[%d]:'%s' => '%s'", __function_name, i,
4894 tr->expression, out);
4895
4896 tr->expression = zbx_strdup(tr->expression, out);
4897
4898 if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode)
4899 {
4900 if (SUCCEED != substitute_expression_functions_results(ifuncs,
4901 tr->recovery_expression, &out, &out_alloc, &tr->new_error))
4902 {
4903 tr->new_value = TRIGGER_VALUE_UNKNOWN;
4904 continue;
4905 }
4906
4907 zabbix_log(LOG_LEVEL_DEBUG, "%s() recovery_expression[%d]:'%s' => '%s'", __function_name, i,
4908 tr->recovery_expression, out);
4909
4910 tr->recovery_expression = zbx_strdup(tr->recovery_expression, out);
4911 }
4912 }
4913
4914 zbx_free(out);
4915
4916 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4917 }
4918
4919 /******************************************************************************
4920 * *
4921 * Function: substitute_functions *
4922 * *
4923 * Purpose: substitute expression functions with their values *
4924 * *
4925 * Parameters: triggers - [IN] vector of DC_TRIGGGER pointers, sorted by *
4926 * triggerids *
4927 * unknown_msgs - vector for storing messages for NOTSUPPORTED *
4928 * items and failed functions *
4929 * *
4930 * Author: Alexei Vladishev, Alexander Vladishev, Aleksandrs Saveljevs *
4931 * *
4932 * Comments: example: "({15}>10) or ({123}=1)" => "(26.416>10) or (0=1)" *
4933 * *
4934 ******************************************************************************/
substitute_functions(zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * unknown_msgs)4935 static void substitute_functions(zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *unknown_msgs)
4936 {
4937 const char *__function_name = "substitute_functions";
4938
4939 zbx_vector_uint64_t functionids;
4940 zbx_hashset_t ifuncs, funcs;
4941
4942 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4943
4944 zbx_vector_uint64_create(&functionids);
4945 zbx_extract_functionids(&functionids, triggers);
4946
4947 if (0 == functionids.values_num)
4948 goto empty;
4949
4950 zbx_hashset_create(&ifuncs, triggers->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC,
4951 ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4952
4953 zbx_hashset_create_ext(&funcs, triggers->values_num, func_hash_func, func_compare_func, func_clean,
4954 ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
4955
4956 zbx_populate_function_items(&functionids, &funcs, &ifuncs, triggers);
4957
4958 if (0 != ifuncs.num_data)
4959 {
4960 zbx_evaluate_item_functions(&funcs, unknown_msgs);
4961 zbx_substitute_functions_results(&ifuncs, triggers);
4962 }
4963
4964 zbx_hashset_destroy(&ifuncs);
4965 zbx_hashset_destroy(&funcs);
4966 empty:
4967 zbx_vector_uint64_destroy(&functionids);
4968
4969 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4970 }
4971
4972 /******************************************************************************
4973 * *
4974 * Function: evaluate_expressions *
4975 * *
4976 * Purpose: evaluate trigger expressions *
4977 * *
4978 * Parameters: triggers - [IN] vector of DC_TRIGGGER pointers, sorted by *
4979 * triggerids *
4980 * *
4981 * Author: Alexei Vladishev *
4982 * *
4983 ******************************************************************************/
evaluate_expressions(zbx_vector_ptr_t * triggers)4984 void evaluate_expressions(zbx_vector_ptr_t *triggers)
4985 {
4986 const char *__function_name = "evaluate_expressions";
4987
4988 DB_EVENT event;
4989 DC_TRIGGER *tr;
4990 int i;
4991 double expr_result;
4992 zbx_vector_ptr_t unknown_msgs; /* pointers to messages about origins of 'unknown' values */
4993 char err[MAX_STRING_LEN];
4994
4995 zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __function_name, triggers->values_num);
4996
4997 event.object = EVENT_OBJECT_TRIGGER;
4998
4999 for (i = 0; i < triggers->values_num; i++)
5000 {
5001 tr = (DC_TRIGGER *)triggers->values[i];
5002
5003 event.value = tr->value;
5004
5005 if (SUCCEED != expand_trigger_macros(&event, tr, err, sizeof(err)))
5006 {
5007 tr->new_error = zbx_dsprintf(tr->new_error, "Cannot evaluate expression: %s", err);
5008 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5009 }
5010 }
5011
5012 /* Assumption: most often there will be no NOTSUPPORTED items and function errors. */
5013 /* Therefore initialize error messages vector but do not reserve any space. */
5014 zbx_vector_ptr_create(&unknown_msgs);
5015
5016 substitute_functions(triggers, &unknown_msgs);
5017
5018 /* calculate new trigger values based on their recovery modes and expression evaluations */
5019 for (i = 0; i < triggers->values_num; i++)
5020 {
5021 tr = (DC_TRIGGER *)triggers->values[i];
5022
5023 if (NULL != tr->new_error)
5024 continue;
5025
5026 if (SUCCEED != evaluate(&expr_result, tr->expression, err, sizeof(err), &unknown_msgs))
5027 {
5028 tr->new_error = zbx_strdup(tr->new_error, err);
5029 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5030 continue;
5031 }
5032
5033 /* trigger expression evaluates to true, set PROBLEM value */
5034 if (SUCCEED != zbx_double_compare(expr_result, 0.0))
5035 {
5036 if (0 == (tr->flags & ZBX_DC_TRIGGER_PROBLEM_EXPRESSION))
5037 {
5038 /* trigger value should remain unchanged and no PROBLEM events should be generated if */
5039 /* problem expression evaluates to true, but trigger recalculation was initiated by a */
5040 /* time-based function or a new value of an item in recovery expression */
5041 tr->new_value = TRIGGER_VALUE_NONE;
5042 }
5043 else
5044 tr->new_value = TRIGGER_VALUE_PROBLEM;
5045
5046 continue;
5047 }
5048
5049 /* otherwise try to recover trigger by setting OK value */
5050 if (TRIGGER_VALUE_PROBLEM == tr->value && TRIGGER_RECOVERY_MODE_NONE != tr->recovery_mode)
5051 {
5052 if (TRIGGER_RECOVERY_MODE_EXPRESSION == tr->recovery_mode)
5053 {
5054 tr->new_value = TRIGGER_VALUE_OK;
5055 continue;
5056 }
5057
5058 /* processing recovery expression mode */
5059 if (SUCCEED != evaluate(&expr_result, tr->recovery_expression, err, sizeof(err), &unknown_msgs))
5060 {
5061 tr->new_error = zbx_strdup(tr->new_error, err);
5062 tr->new_value = TRIGGER_VALUE_UNKNOWN;
5063 continue;
5064 }
5065
5066 if (SUCCEED != zbx_double_compare(expr_result, 0.0))
5067 {
5068 tr->new_value = TRIGGER_VALUE_OK;
5069 continue;
5070 }
5071 }
5072
5073 /* no changes, keep the old value */
5074 tr->new_value = TRIGGER_VALUE_NONE;
5075 }
5076
5077 zbx_vector_ptr_clear_ext(&unknown_msgs, zbx_ptr_free);
5078 zbx_vector_ptr_destroy(&unknown_msgs);
5079
5080 if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
5081 {
5082 for (i = 0; i < triggers->values_num; i++)
5083 {
5084 tr = (DC_TRIGGER *)triggers->values[i];
5085
5086 if (NULL != tr->new_error)
5087 {
5088 zabbix_log(LOG_LEVEL_DEBUG, "%s():expression [%s] cannot be evaluated: %s",
5089 __function_name, tr->expression, tr->new_error);
5090 }
5091 }
5092
5093 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
5094 }
5095 }
5096
5097 /******************************************************************************
5098 * *
5099 * Function: process_simple_macro_token *
5100 * *
5101 * Purpose: trying to resolve the discovery macros in item key parameters *
5102 * in simple macros like {host:key[].func()} *
5103 * *
5104 ******************************************************************************/
process_simple_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,char * error,size_t max_error_len)5105 static int process_simple_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5106 char *error, size_t max_error_len)
5107 {
5108 char *key = NULL, *replace_to = NULL, *dot, *params;
5109 size_t replace_to_offset = 0, replace_to_alloc = 128, lld_start, lld_end;
5110 int ret = FAIL;
5111
5112 if ('{' == (*data)[token->data.simple_macro.host.l] &&
5113 NULL == macro_in_list(*data, token->data.simple_macro.host, simple_host_macros, NULL))
5114 {
5115 goto out;
5116 }
5117
5118 replace_to = (char *)zbx_malloc(NULL, replace_to_alloc);
5119
5120 lld_start = token->data.simple_macro.key.l;
5121 lld_end = token->data.simple_macro.func_param.r - 1;
5122 dot = *data + token->data.simple_macro.key.r + 1;
5123 params = *data + token->data.simple_macro.func_param.l + 1;
5124
5125 /* extract key and substitute macros */
5126 *dot = '\0';
5127 key = zbx_strdup(key, *data + token->data.simple_macro.key.l);
5128 substitute_key_macros(&key, NULL, NULL, jp_row, MACRO_TYPE_ITEM_KEY, NULL, 0);
5129 *dot = '.';
5130
5131 zbx_strcpy_alloc(&replace_to, &replace_to_alloc, &replace_to_offset, key);
5132 zbx_strncpy_alloc(&replace_to, &replace_to_alloc, &replace_to_offset, dot, params - dot);
5133
5134 /* substitute macros in function parameters */
5135 if (SUCCEED != substitute_function_lld_param(params, *data + lld_end - params + 1, 0, &replace_to,
5136 &replace_to_alloc, &replace_to_offset, jp_row, error, max_error_len))
5137 {
5138 goto out;
5139 }
5140
5141 /* replace LLD part in original string and adjust token boundary */
5142 zbx_replace_string(data, lld_start, &lld_end, replace_to);
5143 token->loc.r += lld_end - (token->data.simple_macro.func_param.r - 1);
5144
5145 ret = SUCCEED;
5146 out:
5147 zbx_free(replace_to);
5148 zbx_free(key);
5149
5150 return ret;
5151 }
5152
5153 /******************************************************************************
5154 * *
5155 * Function: process_lld_macro_token *
5156 * *
5157 * Purpose: expand discovery macro in expression *
5158 * *
5159 * Parameters: data - [IN/OUT] the expression containing lld macro *
5160 * token - [IN/OUT] the token with lld macro location data *
5161 * flags - [IN] the flags passed to *
5162 * subtitute_discovery_macros() function *
5163 * jp_row - [IN] discovery data *
5164 * error - [OUT] should be not NULL if *
5165 * ZBX_MACRO_NUMERIC flag is set *
5166 * error_len - [IN] the size of error buffer *
5167 * *
5168 * Return value: Always SUCCEED if numeric flag is not set, otherwise SUCCEED *
5169 * if all discovery macros resolved to numeric values, *
5170 * otherwise FAIL with an error message. *
5171 * *
5172 ******************************************************************************/
process_lld_macro_token(char ** data,zbx_token_t * token,int flags,const struct zbx_json_parse * jp_row,char * error,size_t error_len)5173 static int process_lld_macro_token(char **data, zbx_token_t *token, int flags, const struct zbx_json_parse *jp_row,
5174 char *error, size_t error_len)
5175 {
5176 char c, *replace_to = NULL;
5177 int ret = SUCCEED, l ,r;
5178 size_t replace_to_alloc = 0;
5179
5180 if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
5181 {
5182 l = token->data.lld_func_macro.macro.l;
5183 r = token->data.lld_func_macro.macro.r;
5184 }
5185 else
5186 {
5187 l = token->loc.l;
5188 r = token->loc.r;
5189 }
5190
5191 c = (*data)[r + 1];
5192 (*data)[r + 1] = '\0';
5193
5194 if (SUCCEED != zbx_json_value_by_name_dyn(jp_row, *data + l, &replace_to, &replace_to_alloc, NULL))
5195 {
5196 zabbix_log(LOG_LEVEL_DEBUG, "cannot substitute macro \"%s\": not found in value set", *data + l);
5197
5198 if (0 != (flags & ZBX_TOKEN_NUMERIC))
5199 {
5200 zbx_snprintf(error, error_len, "no value for macro \"%s\"", *data + l);
5201 ret = FAIL;
5202 }
5203
5204 (*data)[r + 1] = c;
5205 zbx_free(replace_to);
5206
5207 return ret;
5208 }
5209
5210 (*data)[r + 1] = c;
5211
5212 if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
5213 {
5214 replace_to_alloc = 0;
5215 if (SUCCEED != (zbx_calculate_macro_function(*data, &token->data.lld_func_macro, &replace_to)))
5216 {
5217 int len = token->data.lld_func_macro.func.r - token->data.lld_func_macro.func.l + 1;
5218
5219 zabbix_log(LOG_LEVEL_DEBUG, "cannot execute function \"%.*s\"", len,
5220 *data + token->data.lld_func_macro.func.l);
5221
5222 if (0 != (flags & ZBX_TOKEN_NUMERIC))
5223 {
5224 zbx_snprintf(error, error_len, "unable to execute function \"%.*s\"", len,
5225 *data + token->data.lld_func_macro.func.l);
5226 ret = FAIL;
5227 }
5228
5229 zbx_free(replace_to);
5230
5231 return ret;
5232 }
5233 }
5234
5235 if (0 != (flags & ZBX_TOKEN_NUMERIC))
5236 {
5237 if (SUCCEED == is_double_suffix(replace_to, ZBX_FLAG_DOUBLE_SUFFIX))
5238 {
5239 wrap_negative_double_suffix(&replace_to, &replace_to_alloc);
5240 }
5241 else
5242 {
5243 zbx_free(replace_to);
5244 zbx_snprintf(error, error_len, "not numeric value in macro \"%.*s\"",
5245 (int)(token->loc.r - token->loc.l + 1), *data + token->loc.l);
5246 return FAIL;
5247 }
5248 }
5249 else if (0 != (flags & ZBX_TOKEN_JSON))
5250 {
5251 zbx_json_escape(&replace_to);
5252 }
5253 else if (0 != (flags & ZBX_TOKEN_XML))
5254 {
5255 char *replace_to_esc;
5256
5257 replace_to_esc = xml_escape_dyn(replace_to);
5258 zbx_free(replace_to);
5259 replace_to = replace_to_esc;
5260 }
5261 else if (0 != (flags & ZBX_TOKEN_REGEXP))
5262 {
5263 zbx_regexp_escape(&replace_to);
5264 }
5265 else if (0 != (flags & ZBX_TOKEN_REGEXP_OUTPUT))
5266 {
5267 char *replace_to_esc;
5268
5269 replace_to_esc = zbx_dyn_escape_string(replace_to, "\\");
5270 zbx_free(replace_to);
5271 replace_to = replace_to_esc;
5272 }
5273 else if (0 != (flags & ZBX_TOKEN_XPATH))
5274 {
5275 xml_escape_xpath(&replace_to);
5276 }
5277 else if (0 != (flags & ZBX_TOKEN_JSONPATH) && ZBX_TOKEN_LLD_MACRO == token->type)
5278 {
5279 char *replace_to_esc;
5280
5281 replace_to_esc = zbx_dyn_escape_string(replace_to, "\\\"");
5282 zbx_free(replace_to);
5283 replace_to = replace_to_esc;
5284 }
5285
5286 if (NULL != replace_to)
5287 {
5288 size_t data_alloc, data_len;
5289
5290 data_alloc = data_len = strlen(*data) + 1;
5291 token->loc.r += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token->loc.l,
5292 token->loc.r - token->loc.l + 1, replace_to, strlen(replace_to));
5293 zbx_free(replace_to);
5294 }
5295
5296 return SUCCEED;
5297 }
5298
5299 /******************************************************************************
5300 * *
5301 * Function: process_user_macro_token *
5302 * *
5303 * Purpose: expand discovery macro in user macro context *
5304 * *
5305 * Parameters: data - [IN/OUT] the expression containing lld macro *
5306 * token - [IN/OUT] the token with user macro location data *
5307 * jp_row - [IN] discovery data *
5308 * *
5309 ******************************************************************************/
process_user_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row)5310 static void process_user_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row)
5311 {
5312 int force_quote;
5313 size_t context_r;
5314 char *context, *context_esc;
5315 zbx_token_user_macro_t *macro = &token->data.user_macro;
5316
5317 /* user macro without context, nothing to replace */
5318 if (0 == token->data.user_macro.context.l)
5319 return;
5320
5321 force_quote = ('"' == (*data)[macro->context.l]);
5322 context = zbx_user_macro_unquote_context_dyn(*data + macro->context.l, macro->context.r - macro->context.l + 1);
5323
5324 /* substitute_lld_macros() can't fail with ZBX_TOKEN_LLD_MACRO or ZBX_TOKEN_LLD_FUNC_MACRO flags set */
5325 substitute_lld_macros(&context, jp_row, ZBX_TOKEN_LLD_MACRO | ZBX_TOKEN_LLD_FUNC_MACRO, NULL, 0);
5326
5327 context_esc = zbx_user_macro_quote_context_dyn(context, force_quote);
5328
5329 context_r = macro->context.r;
5330 zbx_replace_string(data, macro->context.l, &context_r, context_esc);
5331
5332 token->loc.r += context_r - macro->context.r;
5333
5334 zbx_free(context_esc);
5335 zbx_free(context);
5336 }
5337
5338 /******************************************************************************
5339 * *
5340 * Function: substitute_func_macro *
5341 * *
5342 * Purpose: substitute lld macros in function macro parameters *
5343 * *
5344 * Parameters: data - [IN/OUT] pointer to a buffer *
5345 * token - [IN/OUT] the token with function macro location data *
5346 * jp_row - [IN] discovery data *
5347 * error - [OUT] error message *
5348 * max_error_len - [IN] the size of error buffer *
5349 * *
5350 * Return value: SUCCEED - the lld macros were resolved successfully *
5351 * FAIL - otherwise *
5352 * *
5353 ******************************************************************************/
substitute_func_macro(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,char * error,size_t max_error_len)5354 static int substitute_func_macro(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5355 char *error, size_t max_error_len)
5356 {
5357 int ret;
5358 char *exp = NULL;
5359 size_t exp_alloc = 0, exp_offset = 0;
5360 size_t par_l = token->data.func_macro.func_param.l, par_r = token->data.func_macro.func_param.r;
5361
5362 ret = substitute_function_lld_param(*data + par_l + 1, par_r - (par_l + 1), 0, &exp, &exp_alloc, &exp_offset,
5363 jp_row, error, max_error_len);
5364
5365 if (SUCCEED == ret)
5366 {
5367 /* copy what is left including closing parenthesis and replace function parameters */
5368 zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, *data + par_r, token->loc.r - (par_r - 1));
5369 zbx_replace_string(data, par_l + 1, &token->loc.r, exp);
5370 }
5371
5372 zbx_free(exp);
5373
5374 return ret;
5375 }
5376
5377 /******************************************************************************
5378 * *
5379 * Function: substitute_lld_macros *
5380 * *
5381 * Parameters: data - [IN/OUT] pointer to a buffer *
5382 * jp_row - [IN] discovery data *
5383 * flags - [IN] ZBX_MACRO_ANY - all LLD macros will be resolved *
5384 * without validation of the value type *
5385 * ZBX_MACRO_NUMERIC - values for LLD macros should *
5386 * be numeric *
5387 * ZBX_MACRO_SIMPLE - LLD macros, located in the *
5388 * item key parameters in simple macros will be *
5389 * resolved considering quotes. *
5390 * Flag ZBX_MACRO_NUMERIC doesn't affect these *
5391 * macros. *
5392 * ZBX_MACRO_FUNC - function macros will be *
5393 * skipped (lld macros inside function macros will *
5394 * be ignored) for macros specified in func_macros *
5395 * array *
5396 * error - [OUT] should be not NULL if ZBX_MACRO_NUMERIC flag is *
5397 * set *
5398 * max_error_len - [IN] the size of error buffer *
5399 * *
5400 * Return value: Always SUCCEED if numeric flag is not set, otherwise SUCCEED *
5401 * if all discovery macros resolved to numeric values, *
5402 * otherwise FAIL with an error message. *
5403 * *
5404 * Author: Alexander Vladishev *
5405 * *
5406 ******************************************************************************/
substitute_lld_macros(char ** data,const struct zbx_json_parse * jp_row,int flags,char * error,size_t max_error_len)5407 int substitute_lld_macros(char **data, const struct zbx_json_parse *jp_row, int flags, char *error,
5408 size_t max_error_len)
5409 {
5410 const char *__function_name = "substitute_lld_macros";
5411
5412 int ret = SUCCEED, pos = 0;
5413 zbx_token_t token;
5414
5415 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, *data);
5416
5417 while (SUCCEED == ret && SUCCEED == zbx_token_find(*data, pos, &token, ZBX_TOKEN_SEARCH_BASIC))
5418 {
5419 if (0 != (token.type & flags))
5420 {
5421 switch (token.type)
5422 {
5423 case ZBX_TOKEN_LLD_MACRO:
5424 case ZBX_TOKEN_LLD_FUNC_MACRO:
5425 ret = process_lld_macro_token(data, &token, flags, jp_row, error,
5426 max_error_len);
5427 pos = token.loc.r;
5428 break;
5429 case ZBX_TOKEN_USER_MACRO:
5430 process_user_macro_token(data, &token, jp_row);
5431 pos = token.loc.r;
5432 break;
5433 case ZBX_TOKEN_SIMPLE_MACRO:
5434 process_simple_macro_token(data, &token, jp_row, error, max_error_len);
5435 pos = token.loc.r;
5436 break;
5437 case ZBX_TOKEN_FUNC_MACRO:
5438 if (NULL != macro_in_list(*data, token.data.func_macro.macro, mod_macros, NULL))
5439 {
5440 ret = substitute_func_macro(data, &token, jp_row, error, max_error_len);
5441 pos = token.loc.r;
5442 }
5443 break;
5444 }
5445 }
5446
5447 pos++;
5448 }
5449
5450 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s data:'%s'", __function_name, zbx_result_string(ret), *data);
5451
5452 return ret;
5453 }
5454
5455 typedef struct
5456 {
5457 zbx_uint64_t *hostid;
5458 DC_ITEM *dc_item;
5459 const struct zbx_json_parse *jp_row;
5460 int macro_type;
5461 }
5462 replace_key_param_data_t;
5463
5464 /******************************************************************************
5465 * *
5466 * Function: replace_key_param *
5467 * *
5468 * Comments: auxiliary function for substitute_key_macros() *
5469 * *
5470 ******************************************************************************/
replace_key_param_cb(const char * data,int key_type,int level,int num,int quoted,void * cb_data,char ** param)5471 static int replace_key_param_cb(const char *data, int key_type, int level, int num, int quoted, void *cb_data,
5472 char **param)
5473 {
5474 replace_key_param_data_t *replace_key_param_data = (replace_key_param_data_t *)cb_data;
5475 zbx_uint64_t *hostid = replace_key_param_data->hostid;
5476 DC_ITEM *dc_item = replace_key_param_data->dc_item;
5477 const struct zbx_json_parse *jp_row = replace_key_param_data->jp_row;
5478 int macro_type = replace_key_param_data->macro_type, ret = SUCCEED;
5479
5480 ZBX_UNUSED(num);
5481
5482 if (ZBX_KEY_TYPE_ITEM == key_type && 0 == level)
5483 return ret;
5484
5485 if (NULL == strchr(data, '{'))
5486 return ret;
5487
5488 *param = zbx_strdup(NULL, data);
5489
5490 if (0 != level)
5491 unquote_key_param(*param);
5492
5493 if (NULL == jp_row)
5494 substitute_simple_macros(NULL, NULL, NULL, NULL, hostid, NULL, dc_item, NULL, NULL,
5495 param, macro_type, NULL, 0);
5496 else
5497 substitute_lld_macros(param, jp_row, ZBX_MACRO_ANY, NULL, 0);
5498
5499 if (0 != level)
5500 {
5501 if (FAIL == (ret = quote_key_param(param, quoted)))
5502 zbx_free(*param);
5503 }
5504
5505 return ret;
5506 }
5507
5508 /******************************************************************************
5509 * *
5510 * Function: substitute_key_macros *
5511 * *
5512 * Purpose: safely substitutes macros in parameters of an item key and OID *
5513 * *
5514 * Example: key | macro | result | return *
5515 * -------------------------+--------+-------------------+--------- *
5516 * echo.sh[{$MACRO}] | a | echo.sh[a] | SUCCEED *
5517 * echo.sh[{$MACRO}] | a\ | echo.sh[a\] | SUCCEED *
5518 * echo.sh["{$MACRO}"] | a | echo.sh["a"] | SUCCEED *
5519 * echo.sh["{$MACRO}"] | a\ | undefined | FAIL *
5520 * echo.sh[{$MACRO}] | a | echo.sh[" a"] | SUCCEED *
5521 * echo.sh[{$MACRO}] | a\ | undefined | FAIL *
5522 * echo.sh["{$MACRO}"] | a | echo.sh[" a"] | SUCCEED *
5523 * echo.sh["{$MACRO}"] | a\ | undefined | FAIL *
5524 * echo.sh[{$MACRO}] | "a" | echo.sh["\"a\""] | SUCCEED *
5525 * echo.sh[{$MACRO}] | "a"\ | undefined | FAIL *
5526 * echo.sh["{$MACRO}"] | "a" | echo.sh["\"a\""] | SUCCEED *
5527 * echo.sh["{$MACRO}"] | "a"\ | undefined | FAIL *
5528 * echo.sh[{$MACRO}] | a,b | echo.sh["a,b"] | SUCCEED *
5529 * echo.sh[{$MACRO}] | a,b\ | undefined | FAIL *
5530 * echo.sh["{$MACRO}"] | a,b | echo.sh["a,b"] | SUCCEED *
5531 * echo.sh["{$MACRO}"] | a,b\ | undefined | FAIL *
5532 * echo.sh[{$MACRO}] | a] | echo.sh["a]"] | SUCCEED *
5533 * echo.sh[{$MACRO}] | a]\ | undefined | FAIL *
5534 * echo.sh["{$MACRO}"] | a] | echo.sh["a]"] | SUCCEED *
5535 * echo.sh["{$MACRO}"] | a]\ | undefined | FAIL *
5536 * echo.sh[{$MACRO}] | [a | echo.sh["a]"] | SUCCEED *
5537 * echo.sh[{$MACRO}] | [a\ | undefined | FAIL *
5538 * echo.sh["{$MACRO}"] | [a | echo.sh["[a"] | SUCCEED *
5539 * echo.sh["{$MACRO}"] | [a\ | undefined | FAIL *
5540 * ifInOctets.{#SNMPINDEX} | 1 | ifInOctets.1 | SUCCEED *
5541 * *
5542 ******************************************************************************/
substitute_key_macros(char ** data,zbx_uint64_t * hostid,DC_ITEM * dc_item,const struct zbx_json_parse * jp_row,int macro_type,char * error,size_t maxerrlen)5543 int substitute_key_macros(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item, const struct zbx_json_parse *jp_row,
5544 int macro_type, char *error, size_t maxerrlen)
5545 {
5546 const char *__function_name = "substitute_key_macros";
5547 replace_key_param_data_t replace_key_param_data;
5548 int key_type, ret;
5549
5550 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, *data);
5551
5552 replace_key_param_data.hostid = hostid;
5553 replace_key_param_data.dc_item = dc_item;
5554 replace_key_param_data.jp_row = jp_row;
5555 replace_key_param_data.macro_type = macro_type;
5556
5557 switch (macro_type)
5558 {
5559 case MACRO_TYPE_ITEM_KEY:
5560 key_type = ZBX_KEY_TYPE_ITEM;
5561 break;
5562 case MACRO_TYPE_SNMP_OID:
5563 key_type = ZBX_KEY_TYPE_OID;
5564 break;
5565 default:
5566 THIS_SHOULD_NEVER_HAPPEN;
5567 exit(EXIT_FAILURE);
5568 }
5569
5570 ret = replace_key_params_dyn(data, key_type, replace_key_param_cb, &replace_key_param_data, error, maxerrlen);
5571
5572 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s data:'%s'", __function_name, zbx_result_string(ret), *data);
5573
5574 return ret;
5575 }
5576
5577 /******************************************************************************
5578 * *
5579 * Function: substitute_function_lld_param *
5580 * *
5581 * Purpose: substitute lld macros in function parameters *
5582 * *
5583 * Parameters: e - [IN] the function parameter list without *
5584 * enclosing parentheses: *
5585 * <p1>, <p2>, ...<pN> *
5586 * len - [IN] the length of function parameter list *
5587 * key_in_param - [IN] 1 - the first parameter must be host:key *
5588 * 0 - otherwise *
5589 * exp - [IN/OUT] output buffer *
5590 * exp_alloc - [IN/OUT] the size of output buffer *
5591 * exp_offset - [IN/OUT] the current position in output buffer *
5592 * jp_row - [IN] discovery data *
5593 * error - [OUT] error message *
5594 * max_error_len - [IN] the size of error buffer *
5595 * *
5596 * Return value: SUCCEED - the lld macros were resolved successfully *
5597 * FAIL - otherwise *
5598 * *
5599 ******************************************************************************/
substitute_function_lld_param(const char * e,size_t len,unsigned char key_in_param,char ** exp,size_t * exp_alloc,size_t * exp_offset,const struct zbx_json_parse * jp_row,char * error,size_t max_error_len)5600 int substitute_function_lld_param(const char *e, size_t len, unsigned char key_in_param,
5601 char **exp, size_t *exp_alloc, size_t *exp_offset, const struct zbx_json_parse *jp_row,
5602 char *error, size_t max_error_len)
5603 {
5604 const char *__function_name = "substitute_function_lld_param";
5605 int ret = SUCCEED;
5606 size_t sep_pos;
5607 char *param = NULL;
5608 const char *p;
5609
5610 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
5611
5612 if (0 == len)
5613 {
5614 zbx_strcpy_alloc(exp, exp_alloc, exp_offset, "");
5615 goto out;
5616 }
5617
5618 for (p = e; p < len + e ; p += sep_pos + 1)
5619 {
5620 size_t param_pos, param_len, rel_len = len - (p - e);
5621 int quoted;
5622
5623 zbx_function_param_parse(p, ¶m_pos, ¶m_len, &sep_pos);
5624
5625 /* copy what was before the parameter */
5626 zbx_strncpy_alloc(exp, exp_alloc, exp_offset, p, param_pos);
5627
5628 /* prepare the parameter (macro substitutions and quoting) */
5629
5630 zbx_free(param);
5631 param = zbx_function_param_unquote_dyn(p + param_pos, param_len, "ed);
5632
5633 if (1 == key_in_param && p == e)
5634 {
5635 char *key = NULL, *host = NULL;
5636
5637 if (SUCCEED != parse_host_key(param, &host, &key) ||
5638 SUCCEED != substitute_key_macros(&key, NULL, NULL, jp_row,
5639 MACRO_TYPE_ITEM_KEY, NULL, 0))
5640 {
5641 zbx_snprintf(error, max_error_len, "Invalid first parameter \"%s\"", param);
5642 zbx_free(host);
5643 zbx_free(key);
5644 ret = FAIL;
5645 goto out;
5646 }
5647
5648 zbx_free(param);
5649 if (NULL != host)
5650 {
5651 param = zbx_dsprintf(NULL, "%s:%s", host, key);
5652 zbx_free(host);
5653 zbx_free(key);
5654 }
5655 else
5656 param = key;
5657 }
5658 else
5659 substitute_lld_macros(¶m, jp_row, ZBX_MACRO_ANY, NULL, 0);
5660
5661 if (SUCCEED != zbx_function_param_quote(¶m, quoted))
5662 {
5663 zbx_snprintf(error, max_error_len, "Cannot quote parameter \"%s\"", param);
5664 ret = FAIL;
5665 goto out;
5666 }
5667
5668 /* copy the parameter */
5669 zbx_strcpy_alloc(exp, exp_alloc, exp_offset, param);
5670
5671 /* copy what was after the parameter (including separator) */
5672 if (sep_pos < rel_len)
5673 zbx_strncpy_alloc(exp, exp_alloc, exp_offset, p + param_pos + param_len,
5674 sep_pos - param_pos - param_len + 1);
5675 }
5676 out:
5677 zbx_free(param);
5678
5679 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
5680
5681 return ret;
5682 }
5683
5684 /******************************************************************************
5685 * *
5686 * Function: substitute_macros_in_json_pairs *
5687 * *
5688 * Purpose: substitute LLD macros in JSON pairs *
5689 * *
5690 * Parameters: data - [IN/OUT] pointer to a buffer that JSON pair *
5691 * jp_row - [IN] discovery data for LLD macro substitution *
5692 * error - [OUT] reason for JSON pair parsing failure *
5693 * maxerrlen - [IN] the size of error buffer *
5694 * *
5695 * Return value: SUCCEED or FAIL if cannot parse JSON pair *
5696 * *
5697 ******************************************************************************/
substitute_macros_in_json_pairs(char ** data,const struct zbx_json_parse * jp_row,char * error,int maxerrlen)5698 int substitute_macros_in_json_pairs(char **data, const struct zbx_json_parse *jp_row, char *error,
5699 int maxerrlen)
5700 {
5701 const char *__function_name = "substitute_macros_in_json_pairs";
5702 struct zbx_json_parse jp_array, jp_object;
5703 struct zbx_json json;
5704 const char *member, *element = NULL;
5705 char name[MAX_STRING_LEN], value[MAX_STRING_LEN], *p_name = NULL, *p_value = NULL;
5706 int ret = SUCCEED;
5707
5708 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
5709
5710 if ('\0' == **data)
5711 goto exit;
5712
5713 if (SUCCEED != zbx_json_open(*data, &jp_array))
5714 {
5715 zbx_snprintf(error, maxerrlen, "cannot parse query fields: %s", zbx_json_strerror());
5716 ret = FAIL;
5717 goto exit;
5718 }
5719
5720 if (NULL == (element = zbx_json_next(&jp_array, element)))
5721 {
5722 zbx_strlcpy(error, "cannot parse query fields: array is empty", maxerrlen);
5723 ret = FAIL;
5724 goto exit;
5725 }
5726
5727 zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
5728
5729 do
5730 {
5731 if (SUCCEED != zbx_json_brackets_open(element, &jp_object) ||
5732 NULL == (member = zbx_json_pair_next(&jp_object, NULL, name, sizeof(name))) ||
5733 NULL == zbx_json_decodevalue(member, value, sizeof(value), NULL))
5734 {
5735 zbx_snprintf(error, maxerrlen, "cannot parse query fields: %s", zbx_json_strerror());
5736 ret = FAIL;
5737 goto clean;
5738 }
5739
5740 p_name = zbx_strdup(NULL, name);
5741 p_value = zbx_strdup(NULL, value);
5742
5743 substitute_lld_macros(&p_name, jp_row, ZBX_MACRO_ANY, NULL, 0);
5744 substitute_lld_macros(&p_value, jp_row, ZBX_MACRO_ANY, NULL, 0);
5745
5746 zbx_json_addobject(&json, NULL);
5747 zbx_json_addstring(&json, p_name, p_value, ZBX_JSON_TYPE_STRING);
5748 zbx_json_close(&json);
5749 zbx_free(p_name);
5750 zbx_free(p_value);
5751 }
5752 while (NULL != (element = zbx_json_next(&jp_array, element)));
5753
5754 zbx_free(*data);
5755 *data = zbx_strdup(NULL, json.buffer);
5756 clean:
5757 zbx_json_free(&json);
5758 exit:
5759 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
5760
5761 return ret;
5762 }
5763
5764 #ifdef HAVE_LIBXML2
5765 /******************************************************************************
5766 * *
5767 * Function: substitute_macros_in_xml_elements *
5768 * *
5769 * Comments: auxiliary function for substitute_macros_xml() *
5770 * *
5771 ******************************************************************************/
substitute_macros_in_xml_elements(const DC_ITEM * item,const struct zbx_json_parse * jp_row,xmlNode * node)5772 static void substitute_macros_in_xml_elements(const DC_ITEM *item, const struct zbx_json_parse *jp_row,
5773 xmlNode *node)
5774 {
5775 xmlChar *value;
5776 xmlAttr *attr;
5777 char *value_tmp;
5778
5779 for (;NULL != node; node = node->next)
5780 {
5781 switch (node->type)
5782 {
5783 case XML_TEXT_NODE:
5784 if (NULL == (value = xmlNodeGetContent(node)))
5785 break;
5786
5787 value_tmp = zbx_strdup(NULL, (const char *)value);
5788
5789 if (NULL != item)
5790 {
5791 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &item->host, item, NULL,
5792 NULL, &value_tmp, MACRO_TYPE_HTTP_XML, NULL, 0);
5793 }
5794 else
5795 substitute_lld_macros(&value_tmp, jp_row, ZBX_MACRO_XML, NULL, 0);
5796
5797 xmlNodeSetContent(node, (xmlChar *)value_tmp);
5798
5799 zbx_free(value_tmp);
5800 xmlFree(value);
5801 break;
5802 case XML_CDATA_SECTION_NODE:
5803 if (NULL == (value = xmlNodeGetContent(node)))
5804 break;
5805
5806 value_tmp = zbx_strdup(NULL, (const char *)value);
5807
5808 if (NULL != item)
5809 {
5810 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &item->host, item, NULL,
5811 NULL, &value_tmp, MACRO_TYPE_HTTP_RAW, NULL, 0);
5812 }
5813 else
5814 substitute_lld_macros(&value_tmp, jp_row, ZBX_MACRO_ANY, NULL, 0);
5815
5816 xmlNodeSetContent(node, (xmlChar *)value_tmp);
5817
5818 zbx_free(value_tmp);
5819 xmlFree(value);
5820 break;
5821 case XML_ELEMENT_NODE:
5822 for (attr = node->properties; NULL != attr; attr = attr->next)
5823 {
5824 if (NULL == attr->name || NULL == (value = xmlGetProp(node, attr->name)))
5825 continue;
5826
5827 value_tmp = zbx_strdup(NULL, (const char *)value);
5828
5829 if (NULL != item)
5830 {
5831 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &item->host,
5832 item, NULL, NULL, &value_tmp, MACRO_TYPE_HTTP_XML,
5833 NULL, 0);
5834 }
5835 else
5836 substitute_lld_macros(&value_tmp, jp_row, ZBX_MACRO_XML, NULL, 0);
5837
5838 xmlSetProp(node, attr->name, (xmlChar *)value_tmp);
5839
5840 zbx_free(value_tmp);
5841 xmlFree(value);
5842 }
5843 break;
5844 default:
5845 break;
5846 }
5847
5848 substitute_macros_in_xml_elements(item, jp_row, node->children);
5849 }
5850 }
5851 #endif
5852
5853 /******************************************************************************
5854 * *
5855 * Function: substitute_macros_xml *
5856 * *
5857 * Purpose: substitute simple or LLD macros in XML text nodes, attributes of *
5858 * a node or in CDATA section, validate XML *
5859 * *
5860 * Parameters: data - [IN/OUT] pointer to a buffer that contains XML *
5861 * item - [IN] item for simple macro substitution *
5862 * jp_row - [IN] discovery data for LLD macro substitution *
5863 * error - [OUT] reason for XML parsing failure *
5864 * maxerrlen - [IN] the size of error buffer *
5865 * *
5866 * Return value: SUCCEED or FAIL if XML validation has failed *
5867 * *
5868 ******************************************************************************/
substitute_macros_xml(char ** data,const DC_ITEM * item,const struct zbx_json_parse * jp_row,char * error,int maxerrlen)5869 int substitute_macros_xml(char **data, const DC_ITEM *item, const struct zbx_json_parse *jp_row, char *error,
5870 int maxerrlen)
5871 {
5872 #ifndef HAVE_LIBXML2
5873 ZBX_UNUSED(data);
5874 ZBX_UNUSED(item);
5875 ZBX_UNUSED(jp_row);
5876 zbx_snprintf(error, maxerrlen, "Support for XML was not compiled in");
5877 return FAIL;
5878 #else
5879 const char *__function_name = "substitute_macros_xml";
5880 xmlDoc *doc;
5881 xmlErrorPtr pErr;
5882 xmlNode *root_element;
5883 xmlChar *mem;
5884 int size, ret = FAIL;
5885
5886 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
5887
5888 if (NULL == (doc = xmlReadMemory(*data, strlen(*data), "noname.xml", NULL, 0)))
5889 {
5890 if (NULL != (pErr = xmlGetLastError()))
5891 zbx_snprintf(error, maxerrlen, "Cannot parse XML value: %s", pErr->message);
5892 else
5893 zbx_snprintf(error, maxerrlen, "Cannot parse XML value");
5894
5895 goto exit;
5896 }
5897
5898 if (NULL == (root_element = xmlDocGetRootElement(doc)))
5899 {
5900 zbx_snprintf(error, maxerrlen, "Cannot parse XML root");
5901 goto clean;
5902 }
5903
5904 substitute_macros_in_xml_elements(item, jp_row, root_element);
5905 xmlDocDumpMemory(doc, &mem, &size);
5906
5907 if (NULL == mem)
5908 {
5909 if (NULL != (pErr = xmlGetLastError()))
5910 zbx_snprintf(error, maxerrlen, "Cannot save XML: %s", pErr->message);
5911 else
5912 zbx_snprintf(error, maxerrlen, "Cannot save XML");
5913
5914 goto clean;
5915 }
5916
5917 zbx_free(*data);
5918 *data = zbx_malloc(NULL, size + 1);
5919 memcpy(*data, (const char *)mem, size + 1);
5920 xmlFree(mem);
5921 ret = SUCCEED;
5922 clean:
5923 xmlFreeDoc(doc);
5924 exit:
5925 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
5926
5927 return ret;
5928 #endif
5929 }
5930
5931 #ifdef HAVE_LIBXML2
5932 /******************************************************************************
5933 * *
5934 * Function: libxml_handle_error *
5935 * *
5936 * Purpose: libxml2 callback function for error handle *
5937 * *
5938 * Parameters: user_data - [IN/OUT] the user context *
5939 * err - [IN] the libxml2 error message *
5940 * *
5941 ******************************************************************************/
libxml_handle_error(void * user_data,xmlErrorPtr err)5942 static void libxml_handle_error(void *user_data, xmlErrorPtr err)
5943 {
5944 zbx_libxml_error_t *err_ctx;
5945
5946 if (NULL == user_data)
5947 return;
5948
5949 err_ctx = (zbx_libxml_error_t *)user_data;
5950 zbx_strlcat(err_ctx->buf, err->message, err_ctx->len);
5951
5952 if (NULL != err->str1)
5953 zbx_strlcat(err_ctx->buf, err->str1, err_ctx->len);
5954
5955 if (NULL != err->str2)
5956 zbx_strlcat(err_ctx->buf, err->str2, err_ctx->len);
5957
5958 if (NULL != err->str3)
5959 zbx_strlcat(err_ctx->buf, err->str3, err_ctx->len);
5960 }
5961 #endif
5962
5963 /******************************************************************************
5964 * *
5965 * Function: xml_xpath_check *
5966 * *
5967 * Purpose: validate xpath string *
5968 * *
5969 * Parameters: xpath - [IN] the xpath value *
5970 * error - [OUT] the error message buffer *
5971 * errlen - [IN] the size of error message buffer *
5972 * *
5973 * Return value: SUCCEED - the xpath component was parsed successfully *
5974 * FAIL - xpath parsing error *
5975 * *
5976 ******************************************************************************/
xml_xpath_check(const char * xpath,char * error,size_t errlen)5977 int xml_xpath_check(const char *xpath, char *error, size_t errlen)
5978 {
5979 #ifndef HAVE_LIBXML2
5980 ZBX_UNUSED(xpath);
5981 ZBX_UNUSED(error);
5982 ZBX_UNUSED(errlen);
5983 return FAIL;
5984 #else
5985 zbx_libxml_error_t err;
5986 xmlXPathContextPtr ctx;
5987 xmlXPathCompExprPtr p;
5988
5989 err.buf = error;
5990 err.len = errlen;
5991
5992 ctx = xmlXPathNewContext(NULL);
5993 xmlSetStructuredErrorFunc(&err, &libxml_handle_error);
5994
5995 p = xmlXPathCtxtCompile(ctx, (xmlChar *)xpath);
5996 xmlSetStructuredErrorFunc(NULL, NULL);
5997
5998 if (NULL == p)
5999 {
6000 xmlXPathFreeContext(ctx);
6001 return FAIL;
6002 }
6003
6004 xmlXPathFreeCompExpr(p);
6005 xmlXPathFreeContext(ctx);
6006 return SUCCEED;
6007 #endif
6008 }
6009