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 "zbxregexp.h"
21 #include "log.h"
22 #include "zbxembed.h"
23 #include "zbxprometheus.h"
24
25 /* LIBXML2 is used */
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/tree.h>
29 # include <libxml/xpath.h>
30 #endif
31
32 #include "preproc_history.h"
33
34 #include "item_preproc.h"
35
36 extern zbx_es_t es_engine;
37
38 /******************************************************************************
39 * *
40 * Function: item_preproc_numeric_type_hint *
41 * *
42 * Purpose: returns numeric type hint based on item value type *
43 * *
44 * Parameters: value_type - [IN] the item value type *
45 * *
46 * Return value: variant numeric type or none *
47 * *
48 ******************************************************************************/
item_preproc_numeric_type_hint(unsigned char value_type)49 static int item_preproc_numeric_type_hint(unsigned char value_type)
50 {
51 switch (value_type)
52 {
53 case ITEM_VALUE_TYPE_FLOAT:
54 return ZBX_VARIANT_DBL;
55 case ITEM_VALUE_TYPE_UINT64:
56 return ZBX_VARIANT_UI64;
57 default:
58 return ZBX_VARIANT_NONE;
59 }
60 }
61
62 /******************************************************************************
63 * *
64 * Function: item_preproc_convert_value *
65 * *
66 * Purpose: convert variant value to the requested type *
67 * *
68 * Parameters: value - [IN/OUT] the value to convert *
69 * type - [IN] the new value type *
70 * errmsg - [OUT] error message *
71 * *
72 * Return value: SUCCEED - the value was converted successfully *
73 * FAIL - otherwise, errmsg contains the error message *
74 * *
75 ******************************************************************************/
item_preproc_convert_value(zbx_variant_t * value,unsigned char type,char ** errmsg)76 static int item_preproc_convert_value(zbx_variant_t *value, unsigned char type, char **errmsg)
77 {
78 if (FAIL == zbx_variant_convert(value, type))
79 {
80 *errmsg = zbx_dsprintf(*errmsg, "cannot convert value to %s", zbx_get_variant_type_desc(type));
81 return FAIL;
82 }
83
84 return SUCCEED;
85 }
86
87 /******************************************************************************
88 * *
89 * Function: zbx_item_preproc_convert_value_to_numeric *
90 * *
91 * Purpose: converts variant value to numeric *
92 * *
93 * Parameters: value_num - [OUT] the converted value *
94 * value - [IN] the value to convert *
95 * value_type - [IN] item value type *
96 * errmsg - [OUT] error message *
97 * *
98 * Return value: SUCCEED - the value was converted successfully *
99 * FAIL - otherwise *
100 * *
101 ******************************************************************************/
zbx_item_preproc_convert_value_to_numeric(zbx_variant_t * value_num,const zbx_variant_t * value,unsigned char value_type,char ** errmsg)102 int zbx_item_preproc_convert_value_to_numeric(zbx_variant_t *value_num, const zbx_variant_t *value,
103 unsigned char value_type, char **errmsg)
104 {
105 int ret = FAIL, type_hint;
106
107 switch (value->type)
108 {
109 case ZBX_VARIANT_DBL:
110 case ZBX_VARIANT_UI64:
111 zbx_variant_copy(value_num, value);
112 ret = SUCCEED;
113 break;
114 case ZBX_VARIANT_STR:
115 ret = zbx_variant_set_numeric(value_num, value->data.str);
116 break;
117 default:
118 ret = FAIL;
119 }
120
121 if (FAIL == ret)
122 {
123 *errmsg = zbx_strdup(*errmsg, "cannot convert value to numeric type");
124 return FAIL;
125 }
126
127 if (ZBX_VARIANT_NONE != (type_hint = item_preproc_numeric_type_hint(value_type)))
128 zbx_variant_convert(value_num, type_hint);
129
130 return SUCCEED;
131 }
132
133 /******************************************************************************
134 * *
135 * Function: item_preproc_multiplier_variant *
136 * *
137 * Purpose: execute custom multiplier preprocessing operation on variant *
138 * value type *
139 * *
140 * Parameters: value_type - [IN] the item type *
141 * value - [IN/OUT] the value to process *
142 * params - [IN] the operation parameters *
143 * errmsg - [OUT] error message *
144 * *
145 * Return value: SUCCEED - the preprocessing step finished successfully *
146 * FAIL - otherwise, errmsg contains the error message *
147 * *
148 ******************************************************************************/
item_preproc_multiplier_variant(unsigned char value_type,zbx_variant_t * value,const char * params,char ** errmsg)149 static int item_preproc_multiplier_variant(unsigned char value_type, zbx_variant_t *value, const char *params,
150 char **errmsg)
151 {
152 zbx_uint64_t multiplier_ui64, value_ui64;
153 double value_dbl;
154 zbx_variant_t value_num;
155
156 if (FAIL == zbx_item_preproc_convert_value_to_numeric(&value_num, value, value_type, errmsg))
157 return FAIL;
158
159 switch (value_num.type)
160 {
161 case ZBX_VARIANT_DBL:
162 value_dbl = value_num.data.dbl * atof(params);
163 zbx_variant_clear(value);
164 zbx_variant_set_dbl(value, value_dbl);
165 break;
166 case ZBX_VARIANT_UI64:
167 if (SUCCEED == is_uint64(params, &multiplier_ui64))
168 value_ui64 = value_num.data.ui64 * multiplier_ui64;
169 else
170 value_ui64 = (double)value_num.data.ui64 * atof(params);
171
172 zbx_variant_clear(value);
173 zbx_variant_set_ui64(value, value_ui64);
174 break;
175 }
176
177 zbx_variant_clear(&value_num);
178
179 return SUCCEED;
180 }
181
182 /******************************************************************************
183 * *
184 * Function: item_preproc_validate_notsupport *
185 * *
186 * Purpose: executes during notsupported item preprocessing *
187 * *
188 * Return value: FAIL - for further error handling *
189 * *
190 ******************************************************************************/
item_preproc_validate_notsupport(char ** errmsg)191 static int item_preproc_validate_notsupport(char **errmsg)
192 {
193 *errmsg = zbx_dsprintf(*errmsg, "item is not supported");
194 return FAIL;
195 }
196
197 /******************************************************************************
198 * *
199 * Function: item_preproc_multiplier *
200 * *
201 * Purpose: execute custom multiplier preprocessing operation *
202 * *
203 * Parameters: value_type - [IN] the item type *
204 * value - [IN/OUT] the value to process *
205 * params - [IN] the operation parameters *
206 * errmsg - [OUT] error message *
207 * *
208 * Return value: SUCCEED - the preprocessing step finished successfully *
209 * FAIL - otherwise, errmsg contains the error message *
210 * *
211 ******************************************************************************/
item_preproc_multiplier(unsigned char value_type,zbx_variant_t * value,const char * params,char ** errmsg)212 static int item_preproc_multiplier(unsigned char value_type, zbx_variant_t *value, const char *params,
213 char **errmsg)
214 {
215 char buffer[MAX_STRING_LEN];
216 char *err = NULL;
217
218 zbx_strlcpy(buffer, params, sizeof(buffer));
219
220 zbx_trim_float(buffer);
221
222 if (FAIL == is_double(buffer, NULL))
223 err = zbx_dsprintf(NULL, "a numerical value is expected or the value is out of range");
224 else if (SUCCEED == item_preproc_multiplier_variant(value_type, value, buffer, &err))
225 return SUCCEED;
226
227 *errmsg = zbx_dsprintf(*errmsg, "cannot apply multiplier \"%s\" to value of type \"%s\": %s",
228 params, zbx_variant_type_desc(value), err);
229 zbx_free(err);
230
231 return FAIL;
232 }
233
234 /******************************************************************************
235 * *
236 * Function: item_preproc_delta_float *
237 * *
238 * Purpose: execute delta type preprocessing operation *
239 * *
240 * Parameters: value - [IN/OUT] the value to process *
241 * ts - [IN] the value timestamp *
242 * op_type - [IN] the operation type *
243 * history_value - [IN] the item historical data *
244 * history_ts - [IN] the historical data timestamp *
245 * *
246 * Return value: SUCCEED - the value was calculated successfully *
247 * FAIL - otherwise *
248 * *
249 ******************************************************************************/
item_preproc_delta_float(zbx_variant_t * value,const zbx_timespec_t * ts,unsigned char op_type,const zbx_variant_t * history_value,const zbx_timespec_t * history_ts)250 static int item_preproc_delta_float(zbx_variant_t *value, const zbx_timespec_t *ts, unsigned char op_type,
251 const zbx_variant_t *history_value, const zbx_timespec_t *history_ts)
252 {
253 if (0 == history_ts->sec || history_value->data.dbl > value->data.dbl)
254 return FAIL;
255
256 switch (op_type)
257 {
258 case ZBX_PREPROC_DELTA_SPEED:
259 if (0 <= zbx_timespec_compare(history_ts, ts))
260 return FAIL;
261
262 value->data.dbl = (value->data.dbl - history_value->data.dbl) /
263 ((ts->sec - history_ts->sec) +
264 (double)(ts->ns - history_ts->ns) / 1000000000);
265 break;
266 case ZBX_PREPROC_DELTA_VALUE:
267 value->data.dbl = value->data.dbl - history_value->data.dbl;
268 break;
269 }
270
271 return SUCCEED;
272 }
273
274 /******************************************************************************
275 * *
276 * Function: item_preproc_delta_uint64 *
277 * *
278 * Purpose: execute delta type preprocessing operation *
279 * *
280 * Parameters: value - [IN/OUT] the value to process *
281 * ts - [IN] the value timestamp *
282 * op_type - [IN] the operation type *
283 * history_value - [IN] the item historical data *
284 * history_ts - [IN] the historical data timestamp *
285 * *
286 * Return value: SUCCEED - the value was calculated successfully *
287 * FAIL - otherwise *
288 * *
289 ******************************************************************************/
item_preproc_delta_uint64(zbx_variant_t * value,const zbx_timespec_t * ts,unsigned char op_type,const zbx_variant_t * history_value,const zbx_timespec_t * history_ts)290 static int item_preproc_delta_uint64(zbx_variant_t *value, const zbx_timespec_t *ts, unsigned char op_type,
291 const zbx_variant_t *history_value, const zbx_timespec_t *history_ts)
292 {
293 if (0 == history_ts->sec || history_value->data.ui64 > value->data.ui64)
294 return FAIL;
295
296 switch (op_type)
297 {
298 case ZBX_PREPROC_DELTA_SPEED:
299 if (0 <= zbx_timespec_compare(history_ts, ts))
300 return FAIL;
301
302 value->data.ui64 = (value->data.ui64 - history_value->data.ui64) /
303 ((ts->sec - history_ts->sec) +
304 (double)(ts->ns - history_ts->ns) / 1000000000);
305 break;
306 case ZBX_PREPROC_DELTA_VALUE:
307 value->data.ui64 = value->data.ui64 - history_value->data.ui64;
308 break;
309 }
310
311 return SUCCEED;
312 }
313
314 /******************************************************************************
315 * *
316 * Function: item_preproc_delta *
317 * *
318 * Purpose: execute delta type preprocessing operation *
319 * *
320 * Parameters: value_type - [IN] the item value type *
321 * value - [IN/OUT] the value to process *
322 * ts - [IN] the value timestamp *
323 * op_type - [IN] the operation type *
324 * history_value - [IN/OUT] the historical (previous) data *
325 * history_ts - [IN/OUT] the timestamp of the historical data *
326 * errmsg - [OUT] error message *
327 * *
328 * Return value: SUCCEED - the value was calculated successfully *
329 * FAIL - otherwise *
330 * *
331 ******************************************************************************/
item_preproc_delta(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,unsigned char op_type,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)332 static int item_preproc_delta(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
333 unsigned char op_type, zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
334 {
335 zbx_variant_t value_num;
336
337 if (FAIL == zbx_item_preproc_convert_value_to_numeric(&value_num, value, value_type, errmsg))
338 return FAIL;
339
340 zbx_variant_clear(value);
341
342 if (ZBX_VARIANT_NONE != history_value->type)
343 {
344 int ret;
345
346 zbx_variant_copy(value, &value_num);
347
348 if (ZBX_VARIANT_DBL == value->type || ZBX_VARIANT_DBL == history_value->type)
349 {
350 zbx_variant_convert(value, ZBX_VARIANT_DBL);
351 zbx_variant_convert(history_value, ZBX_VARIANT_DBL);
352 ret = item_preproc_delta_float(value, ts, op_type, history_value, history_ts);
353 }
354 else
355 {
356 zbx_variant_convert(value, ZBX_VARIANT_UI64);
357 zbx_variant_convert(history_value, ZBX_VARIANT_UI64);
358 ret = item_preproc_delta_uint64(value, ts, op_type, history_value, history_ts);
359 }
360
361 if (SUCCEED != ret)
362 zbx_variant_clear(value);
363 }
364
365 *history_ts = *ts;
366 zbx_variant_clear(history_value);
367 zbx_variant_copy(history_value, &value_num);
368 zbx_variant_clear(&value_num);
369
370 return SUCCEED;
371 }
372
373 /******************************************************************************
374 * *
375 * Function: item_preproc_delta_value *
376 * *
377 * Purpose: execute delta (simple change) preprocessing operation *
378 * *
379 * Parameters: value_type - [IN] the item value type *
380 * value - [IN/OUT] the value to process *
381 * ts - [IN] the value timestamp *
382 * history_value - [IN] historical data of item with delta *
383 * preprocessing operation *
384 * errmsg - [OUT] error message *
385 * *
386 * Return value: SUCCEED - the value was calculated successfully *
387 * FAIL - otherwise *
388 * *
389 ******************************************************************************/
item_preproc_delta_value(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)390 static int item_preproc_delta_value(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
391 zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
392 {
393 char *err = NULL;
394
395 if (SUCCEED == item_preproc_delta(value_type, value, ts, ZBX_PREPROC_DELTA_VALUE, history_value, history_ts,
396 &err))
397 {
398 return SUCCEED;
399 }
400
401 *errmsg = zbx_dsprintf(*errmsg, "cannot calculate delta (simple change) for value of type"
402 " \"%s\": %s", zbx_variant_type_desc(value), err);
403
404 zbx_free(err);
405
406 return FAIL;
407 }
408
409 /******************************************************************************
410 * *
411 * Function: item_preproc_delta_speed *
412 * *
413 * Purpose: execute delta (speed per second) preprocessing operation *
414 * *
415 * Parameters: value_type - [IN] the item value type *
416 * value - [IN/OUT] the value to process *
417 * ts - [IN] the value timestamp *
418 * history_value - [IN] historical data of item with delta *
419 * preprocessing operation *
420 * errmsg - [OUT] error message *
421 * *
422 * Return value: SUCCEED - the value was calculated successfully *
423 * FAIL - otherwise *
424 * *
425 ******************************************************************************/
item_preproc_delta_speed(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)426 static int item_preproc_delta_speed(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
427 zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
428 {
429 char *err = NULL;
430
431 if (SUCCEED == item_preproc_delta(value_type, value, ts, ZBX_PREPROC_DELTA_SPEED, history_value, history_ts,
432 &err))
433 {
434 return SUCCEED;
435 }
436
437 *errmsg = zbx_dsprintf(*errmsg, "cannot calculate delta (speed per second) for value of type"
438 " \"%s\": %s", zbx_variant_type_desc(value), err);
439
440 zbx_free(err);
441
442 return FAIL;
443 }
444
445 /******************************************************************************
446 * *
447 * Function: unescape_param *
448 * *
449 * Purpose: copy first n chars from in to out, unescape escaped characters *
450 * during copying *
451 * *
452 * Parameters: op_type - [IN] the operation type *
453 * in - [IN] the value to unescape *
454 * len - [IN] the length of the value to be unescaped *
455 * out - [OUT] the value to process *
456 * *
457 ******************************************************************************/
unescape_param(int op_type,const char * in,int len,char * out)458 static void unescape_param(int op_type, const char *in, int len, char *out)
459 {
460 const char *end = in + len;
461
462 for (;in < end; in++, out++)
463 {
464 if ('\\' == *in)
465 {
466 switch (*(++in))
467 {
468 case 's':
469 *out = ' ';
470 break;
471 case 'r':
472 *out = '\r';
473 break;
474 case 'n':
475 *out = '\n';
476 break;
477 case 't':
478 *out = '\t';
479 break;
480 case '\\':
481 if (ZBX_PREPROC_STR_REPLACE == op_type)
482 {
483 *out = '\\';
484 break;
485 }
486 ZBX_FALLTHROUGH;
487 default:
488 *out = *(--in);
489 }
490 }
491 else
492 *out = *in;
493 }
494
495 *out = '\0';
496 }
497
498 /******************************************************************************
499 * *
500 * Function: item_preproc_trim *
501 * *
502 * Purpose: execute trim type preprocessing operation *
503 * *
504 * Parameters: value - [IN/OUT] the value to process *
505 * op_type - [IN] the operation type *
506 * params - [IN] the characters to trim *
507 * errmsg - [OUT] error message *
508 * *
509 * Return value: SUCCEED - the value was trimmed successfully *
510 * FAIL - otherwise *
511 * *
512 ******************************************************************************/
item_preproc_trim(zbx_variant_t * value,unsigned char op_type,const char * params,char ** errmsg)513 static int item_preproc_trim(zbx_variant_t *value, unsigned char op_type, const char *params, char **errmsg)
514 {
515 char params_raw[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1];
516
517 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
518 return FAIL;
519
520 unescape_param(op_type, params, strlen(params), params_raw);
521
522 if (ZBX_PREPROC_LTRIM == op_type || ZBX_PREPROC_TRIM == op_type)
523 zbx_ltrim(value->data.str, params_raw);
524
525 if (ZBX_PREPROC_RTRIM == op_type || ZBX_PREPROC_TRIM == op_type)
526 zbx_rtrim(value->data.str, params_raw);
527
528 return SUCCEED;
529 }
530
531 /******************************************************************************
532 * *
533 * Function: item_preproc_rtrim *
534 * *
535 * Purpose: execute right trim preprocessing operation *
536 * *
537 * Parameters: value - [IN/OUT] the value to process *
538 * params - [IN] the characters to trim *
539 * errmsg - [OUT] error message *
540 * *
541 * Return value: SUCCEED - the value was trimmed successfully *
542 * FAIL - otherwise *
543 * *
544 ******************************************************************************/
item_preproc_rtrim(zbx_variant_t * value,const char * params,char ** errmsg)545 static int item_preproc_rtrim(zbx_variant_t *value, const char *params, char **errmsg)
546 {
547 char *err = NULL, *characters;
548
549 if (SUCCEED == item_preproc_trim(value, ZBX_PREPROC_RTRIM, params, &err))
550 return SUCCEED;
551
552 characters = zbx_str_printable_dyn(params);
553 *errmsg = zbx_dsprintf(*errmsg, "cannot perform right trim of \"%s\" for value of type \"%s\": %s",
554 characters, zbx_variant_type_desc(value), err);
555
556 zbx_free(characters);
557 zbx_free(err);
558
559 return FAIL;
560 }
561
562 /******************************************************************************
563 * *
564 * Function: item_preproc_ltrim *
565 * *
566 * Purpose: execute left trim preprocessing operation *
567 * *
568 * Parameters: value - [IN/OUT] the value to process *
569 * params - [IN] the characters to trim *
570 * errmsg - [OUT] error message *
571 * *
572 * Return value: SUCCEED - the value was trimmed successfully *
573 * FAIL - otherwise *
574 * *
575 ******************************************************************************/
item_preproc_ltrim(zbx_variant_t * value,const char * params,char ** errmsg)576 static int item_preproc_ltrim(zbx_variant_t *value, const char *params, char **errmsg)
577 {
578 char *err = NULL, *characters;
579
580 if (SUCCEED == item_preproc_trim(value, ZBX_PREPROC_LTRIM, params, &err))
581 return SUCCEED;
582
583 characters = zbx_str_printable_dyn(params);
584 *errmsg = zbx_dsprintf(*errmsg, "cannot perform left trim of \"%s\" for value of type \"%s\": %s",
585 characters, zbx_variant_type_desc(value), err);
586
587 zbx_free(characters);
588 zbx_free(err);
589
590 return FAIL;
591 }
592
593 /******************************************************************************
594 * *
595 * Function: item_preproc_lrtrim *
596 * *
597 * Purpose: execute left and right trim preprocessing operation *
598 * *
599 * Parameters: value - [IN/OUT] the value to process *
600 * params - [IN] the characters to trim *
601 * errmsg - [OUT] error message *
602 * *
603 * Return value: SUCCEED - the value was trimmed successfully *
604 * FAIL - otherwise *
605 * *
606 ******************************************************************************/
item_preproc_lrtrim(zbx_variant_t * value,const char * params,char ** errmsg)607 static int item_preproc_lrtrim(zbx_variant_t *value, const char *params, char **errmsg)
608 {
609 char *err = NULL, *characters;
610
611 if (SUCCEED == item_preproc_trim(value, ZBX_PREPROC_TRIM, params, &err))
612 return SUCCEED;
613
614 characters = zbx_str_printable_dyn(params);
615 *errmsg = zbx_dsprintf(*errmsg, "cannot perform trim of \"%s\" for value of type \"%s\": %s",
616 characters, zbx_variant_type_desc(value), err);
617
618 zbx_free(characters);
619 zbx_free(err);
620
621 return FAIL;
622 }
623
624 /******************************************************************************
625 * *
626 * Function: item_preproc_2dec *
627 * *
628 * Purpose: execute decimal value conversion operation *
629 * *
630 * Parameters: value - [IN/OUT] the value to convert *
631 * op_type - [IN] the operation type *
632 * errmsg - [OUT] error message *
633 * *
634 * Return value: SUCCEED - the value was converted successfully *
635 * FAIL - otherwise *
636 * *
637 ******************************************************************************/
item_preproc_2dec(zbx_variant_t * value,unsigned char op_type,char ** errmsg)638 static int item_preproc_2dec(zbx_variant_t *value, unsigned char op_type, char **errmsg)
639 {
640 zbx_uint64_t value_ui64;
641
642 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
643 return FAIL;
644
645 zbx_ltrim(value->data.str, " \"");
646 zbx_rtrim(value->data.str, " \"\n\r");
647
648 switch (op_type)
649 {
650 case ZBX_PREPROC_BOOL2DEC:
651 if (SUCCEED != is_boolean(value->data.str, &value_ui64))
652 {
653 *errmsg = zbx_strdup(NULL, "invalid value format");
654 return FAIL;
655 }
656 break;
657 case ZBX_PREPROC_OCT2DEC:
658 if (SUCCEED != is_uoct(value->data.str))
659 {
660 *errmsg = zbx_strdup(NULL, "invalid value format");
661 return FAIL;
662 }
663 ZBX_OCT2UINT64(value_ui64, value->data.str);
664 break;
665 case ZBX_PREPROC_HEX2DEC:
666 if (SUCCEED != is_uhex(value->data.str))
667 {
668 if (SUCCEED != is_hex_string(value->data.str))
669 {
670 *errmsg = zbx_strdup(NULL, "invalid value format");
671 return FAIL;
672 }
673
674 zbx_remove_chars(value->data.str, " \n");
675 }
676 ZBX_HEX2UINT64(value_ui64, value->data.str);
677 break;
678 default:
679 *errmsg = zbx_strdup(NULL, "unknown operation type");
680 return FAIL;
681 }
682
683 zbx_variant_clear(value);
684 zbx_variant_set_ui64(value, value_ui64);
685
686 return SUCCEED;
687 }
688
689 /******************************************************************************
690 * *
691 * Function: item_preproc_bool2dec *
692 * *
693 * Purpose: execute boolean to decimal value conversion operation *
694 * *
695 * Parameters: value - [IN/OUT] the value to convert *
696 * errmsg - [OUT] error message *
697 * *
698 * Return value: SUCCEED - the value was converted successfully *
699 * FAIL - otherwise *
700 * *
701 ******************************************************************************/
item_preproc_bool2dec(zbx_variant_t * value,char ** errmsg)702 static int item_preproc_bool2dec(zbx_variant_t *value, char **errmsg)
703 {
704 char *err = NULL;
705
706 if (SUCCEED == item_preproc_2dec(value, ZBX_PREPROC_BOOL2DEC, &err))
707 return SUCCEED;
708
709 *errmsg = zbx_dsprintf(*errmsg, "cannot convert value of type \"%s\" from boolean format: %s",
710 zbx_variant_type_desc(value), err);
711
712 zbx_free(err);
713
714 return FAIL;
715 }
716
717 /******************************************************************************
718 * *
719 * Function: item_preproc_oct2dec *
720 * *
721 * Purpose: execute octal to decimal value conversion operation *
722 * *
723 * Parameters: value - [IN/OUT] the value to convert *
724 * errmsg - [OUT] error message *
725 * *
726 * Return value: SUCCEED - the value was converted successfully *
727 * FAIL - otherwise *
728 * *
729 ******************************************************************************/
item_preproc_oct2dec(zbx_variant_t * value,char ** errmsg)730 static int item_preproc_oct2dec(zbx_variant_t *value, char **errmsg)
731 {
732 char *err = NULL;
733
734 if (SUCCEED == item_preproc_2dec(value, ZBX_PREPROC_OCT2DEC, &err))
735 return SUCCEED;
736
737 *errmsg = zbx_dsprintf(*errmsg, "cannot convert value of type \"%s\" from octal format: %s",
738 zbx_variant_type_desc(value), err);
739
740 zbx_free(err);
741
742 return FAIL;
743 }
744
745 /******************************************************************************
746 * *
747 * Function: item_preproc_hex2dec *
748 * *
749 * Purpose: execute hexadecimal to decimal value conversion operation *
750 * *
751 * Parameters: value - [IN/OUT] the value to convert *
752 * errmsg - [OUT] error message *
753 * *
754 * Return value: SUCCEED - the value was converted successfully *
755 * FAIL - otherwise *
756 * *
757 ******************************************************************************/
item_preproc_hex2dec(zbx_variant_t * value,char ** errmsg)758 static int item_preproc_hex2dec(zbx_variant_t *value, char **errmsg)
759 {
760 char *err = NULL;
761
762 if (SUCCEED == item_preproc_2dec(value, ZBX_PREPROC_HEX2DEC, &err))
763 return SUCCEED;
764
765 *errmsg = zbx_dsprintf(*errmsg, "cannot convert value of type \"%s\" from hexadecimal format: %s",
766 zbx_variant_type_desc(value), err);
767
768 zbx_free(err);
769
770 return FAIL;
771 }
772
773 /******************************************************************************
774 * *
775 * Function: item_preproc_regsub_op *
776 * *
777 * Purpose: execute regular expression substitution operation *
778 * *
779 * Parameters: value - [IN/OUT] the value to process *
780 * params - [IN] the operation parameters *
781 * errmsg - [OUT] error message *
782 * *
783 * Return value: SUCCEED - the value was processed successfully *
784 * FAIL - otherwise *
785 * *
786 ******************************************************************************/
item_preproc_regsub_op(zbx_variant_t * value,const char * params,char ** errmsg)787 static int item_preproc_regsub_op(zbx_variant_t *value, const char *params, char **errmsg)
788 {
789 char pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1];
790 char *output, *new_value = NULL;
791 const char *regex_error;
792 zbx_regexp_t *regex = NULL;
793
794 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
795 return FAIL;
796
797 zbx_strlcpy(pattern, params, sizeof(pattern));
798
799 if (NULL == (output = strchr(pattern, '\n')))
800 {
801 *errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
802 return FAIL;
803 }
804
805 *output++ = '\0';
806
807 if (FAIL == zbx_regexp_compile_ext(pattern, ®ex, 0, ®ex_error)) /* PCRE_MULTILINE is not used here */
808 {
809 *errmsg = zbx_dsprintf(*errmsg, "invalid regular expression: %s", regex_error);
810 return FAIL;
811 }
812
813 if (FAIL == zbx_mregexp_sub_precompiled(value->data.str, regex, output, ZBX_MAX_RECV_DATA_SIZE, &new_value))
814 {
815 *errmsg = zbx_strdup(*errmsg, "pattern does not match");
816 zbx_regexp_free(regex);
817 return FAIL;
818 }
819
820 zbx_variant_clear(value);
821 zbx_variant_set_str(value, new_value);
822
823 zbx_regexp_free(regex);
824
825 return SUCCEED;
826 }
827
828 /******************************************************************************
829 * *
830 * Function: item_preproc_regsub *
831 * *
832 * Purpose: execute regular expression substitution operation *
833 * *
834 * Parameters: value - [IN/OUT] the value to process *
835 * params - [IN] the operation parameters *
836 * errmsg - [OUT] error message *
837 * *
838 * Return value: SUCCEED - the value was processed successfully *
839 * FAIL - otherwise *
840 * *
841 ******************************************************************************/
item_preproc_regsub(zbx_variant_t * value,const char * params,char ** errmsg)842 static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **errmsg)
843 {
844 char *err = NULL, *ptr;
845 int len;
846
847 if (SUCCEED == item_preproc_regsub_op(value, params, &err))
848 return SUCCEED;
849
850 if (NULL == (ptr = strchr(params, '\n')))
851 len = strlen(params);
852 else
853 len = ptr - params;
854
855 *errmsg = zbx_dsprintf(*errmsg, "cannot perform regular expression \"%.*s\" match for value of type \"%s\": %s",
856 len, params, zbx_variant_type_desc(value), err);
857
858 zbx_free(err);
859
860 return FAIL;
861 }
862
863 /******************************************************************************
864 * *
865 * Function: item_preproc_jsonpath_op *
866 * *
867 * Purpose: execute jsonpath query *
868 * *
869 * Parameters: value - [IN/OUT] the value to process *
870 * params - [IN] the operation parameters *
871 * errmsg - [OUT] error message *
872 * *
873 * Return value: SUCCEED - the value was processed successfully *
874 * FAIL - otherwise *
875 * *
876 ******************************************************************************/
item_preproc_jsonpath_op(zbx_variant_t * value,const char * params,char ** errmsg)877 static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, char **errmsg)
878 {
879 struct zbx_json_parse jp;
880 char *data = NULL;
881
882 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
883 return FAIL;
884
885 if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_jsonpath_query(&jp, params, &data))
886 {
887 *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
888 return FAIL;
889 }
890
891 if (NULL == data)
892 {
893 *errmsg = zbx_strdup(*errmsg, "no data matches the specified path");
894 return FAIL;
895 }
896
897 zbx_variant_clear(value);
898 zbx_variant_set_str(value, data);
899
900 return SUCCEED;
901 }
902
903 /******************************************************************************
904 * *
905 * Function: item_preproc_jsonpath *
906 * *
907 * Purpose: execute jsonpath query *
908 * *
909 * Parameters: value - [IN/OUT] the value to process *
910 * params - [IN] the operation parameters *
911 * errmsg - [OUT] error message *
912 * *
913 * Return value: SUCCEED - the value was processed successfully *
914 * FAIL - otherwise *
915 * *
916 ******************************************************************************/
item_preproc_jsonpath(zbx_variant_t * value,const char * params,char ** errmsg)917 static int item_preproc_jsonpath(zbx_variant_t *value, const char *params, char **errmsg)
918 {
919 char *err = NULL;
920
921 if (SUCCEED == item_preproc_jsonpath_op(value, params, &err))
922 return SUCCEED;
923
924 *errmsg = zbx_dsprintf(*errmsg, "cannot extract value from json by path \"%s\": %s", params, err);
925
926 zbx_free(err);
927
928 return FAIL;
929 }
930
931 /******************************************************************************
932 * *
933 * Function: item_preproc_xpath *
934 * *
935 * Purpose: execute xpath query *
936 * *
937 * Parameters: value - [IN/OUT] the value to process *
938 * params - [IN] the operation parameters *
939 * errmsg - [OUT] error message *
940 * *
941 * Return value: SUCCEED - the value was processed successfully *
942 * FAIL - otherwise *
943 * *
944 ******************************************************************************/
item_preproc_xpath(zbx_variant_t * value,const char * params,char ** errmsg)945 static int item_preproc_xpath(zbx_variant_t *value, const char *params, char **errmsg)
946 {
947 char *err = NULL;
948
949 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
950 return FAIL;
951
952 if (SUCCEED == zbx_query_xpath(value, params, &err))
953 return SUCCEED;
954
955 *errmsg = zbx_dsprintf(*errmsg, "cannot extract XML value with xpath \"%s\": %s", params, err);
956 zbx_free(err);
957
958 return FAIL;
959 }
960
961 /******************************************************************************
962 * *
963 * Function: item_preproc_validate_range *
964 * *
965 * Purpose: validates value to be within the specified range *
966 * Parameters: value_type - [IN] the item type *
967 * value - [IN/OUT] the value to process *
968 * params - [IN] the operation parameters *
969 * errmsg - [OUT] error message *
970 * *
971 * Return value: SUCCEED - the preprocessing step finished successfully *
972 * FAIL - otherwise, errmsg contains the error message *
973 * *
974 ******************************************************************************/
item_preproc_validate_range(unsigned char value_type,const zbx_variant_t * value,const char * params,char ** errmsg)975 static int item_preproc_validate_range(unsigned char value_type, const zbx_variant_t *value, const char *params,
976 char **errmsg)
977 {
978 zbx_variant_t value_num;
979 char min[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *max;
980 zbx_variant_t range_min, range_max;
981 int ret = FAIL;
982
983 if (FAIL == zbx_item_preproc_convert_value_to_numeric(&value_num, value, value_type, errmsg))
984 return FAIL;
985
986 zbx_variant_set_none(&range_min);
987 zbx_variant_set_none(&range_max);
988
989 zbx_strlcpy(min, params, sizeof(min));
990 if (NULL == (max = strchr(min, '\n')))
991 {
992 *errmsg = zbx_strdup(*errmsg, "validation range is not specified");
993 goto out;
994 }
995
996 *max++ = '\0';
997
998 if ('\0' != *min && FAIL == zbx_variant_set_numeric(&range_min, min))
999 {
1000 *errmsg = zbx_dsprintf(*errmsg, "validation range minimum value is invalid: %s", min);
1001 goto out;
1002 }
1003
1004 if ('\0' != *max && FAIL == zbx_variant_set_numeric(&range_max, max))
1005 {
1006 *errmsg = zbx_dsprintf(*errmsg, "validation range maximum value is invalid: %s", max);
1007 goto out;
1008 }
1009
1010 if ((ZBX_VARIANT_NONE != range_min.type && 0 > zbx_variant_compare(&value_num, &range_min)) ||
1011 (ZBX_VARIANT_NONE != range_max.type && 0 > zbx_variant_compare(&range_max, &value_num)))
1012 {
1013 size_t errmsg_alloc = 0, errmsg_offset = 0;
1014
1015 zbx_free(*errmsg);
1016
1017 zbx_strcpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, "value is");
1018 if ('\0' != *min)
1019 {
1020 zbx_snprintf_alloc(errmsg, &errmsg_alloc, &errmsg_offset, " less than %s", min);
1021 if ('\0' != *max)
1022 zbx_strcpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, " or");
1023 }
1024 if ('\0' != *max)
1025 zbx_snprintf_alloc(errmsg, &errmsg_alloc, &errmsg_offset, " greater than %s", max);
1026
1027 goto out;
1028 }
1029
1030 ret = SUCCEED;
1031 out:
1032 zbx_variant_clear(&value_num);
1033 zbx_variant_clear(&range_min);
1034 zbx_variant_clear(&range_max);
1035
1036 return ret;
1037 }
1038
1039 /******************************************************************************
1040 * *
1041 * Function: item_preproc_validate_regex *
1042 * *
1043 * Purpose: validates value to match regular expression *
1044 * Parameters: value_type - [IN] the item type *
1045 * value - [IN/OUT] the value to process *
1046 * params - [IN] the operation parameters *
1047 * errmsg - [OUT] error message *
1048 * *
1049 * Return value: SUCCEED - the preprocessing step finished successfully *
1050 * FAIL - otherwise, errmsg contains the error message *
1051 * *
1052 ******************************************************************************/
item_preproc_validate_regex(const zbx_variant_t * value,const char * params,char ** error)1053 static int item_preproc_validate_regex(const zbx_variant_t *value, const char *params, char **error)
1054 {
1055 zbx_variant_t value_str;
1056 int ret = FAIL;
1057 zbx_regexp_t *regex;
1058 const char *errptr = NULL;
1059 char *errmsg;
1060
1061 zbx_variant_copy(&value_str, value);
1062
1063 if (FAIL == zbx_variant_convert(&value_str, ZBX_VARIANT_STR))
1064 {
1065 errmsg = zbx_strdup(NULL, "cannot convert value to string");
1066 goto out;
1067 }
1068
1069 if (FAIL == zbx_regexp_compile(params, ®ex, &errptr))
1070 {
1071 errmsg = zbx_dsprintf(NULL, "invalid regular expression pattern: %s", errptr);
1072 goto out;
1073 }
1074
1075 if (0 != zbx_regexp_match_precompiled(value_str.data.str, regex))
1076 errmsg = zbx_strdup(NULL, "value does not match regular expression");
1077 else
1078 ret = SUCCEED;
1079
1080 zbx_regexp_free(regex);
1081 out:
1082 zbx_variant_clear(&value_str);
1083
1084 if (FAIL == ret)
1085 {
1086 *error = zbx_dsprintf(*error, "cannot perform regular expression \"%s\" validation"
1087 " for value of type \"%s\": %s",
1088 params, zbx_variant_type_desc(value), errmsg);
1089 zbx_free(errmsg);
1090 }
1091
1092 return ret;
1093 }
1094
1095 /******************************************************************************
1096 * *
1097 * Function: item_preproc_validate_not_regex *
1098 * *
1099 * Purpose: validates value to not match regular expression *
1100 * Parameters: value_type - [IN] the item type *
1101 * value - [IN/OUT] the value to process *
1102 * params - [IN] the operation parameters *
1103 * errmsg - [OUT] error message *
1104 * *
1105 * Return value: SUCCEED - the preprocessing step finished successfully *
1106 * FAIL - otherwise, errmsg contains the error message *
1107 * *
1108 ******************************************************************************/
item_preproc_validate_not_regex(const zbx_variant_t * value,const char * params,char ** error)1109 static int item_preproc_validate_not_regex(const zbx_variant_t *value, const char *params, char **error)
1110 {
1111 zbx_variant_t value_str;
1112 int ret = FAIL;
1113 zbx_regexp_t *regex;
1114 const char *errptr = NULL;
1115 char *errmsg;
1116
1117 zbx_variant_copy(&value_str, value);
1118
1119 if (FAIL == zbx_variant_convert(&value_str, ZBX_VARIANT_STR))
1120 {
1121 errmsg = zbx_strdup(NULL, "cannot convert value to string");
1122 goto out;
1123 }
1124
1125 if (FAIL == zbx_regexp_compile(params, ®ex, &errptr))
1126 {
1127 errmsg = zbx_dsprintf(NULL, "invalid regular expression pattern: %s", errptr);
1128 goto out;
1129 }
1130
1131 if (0 == zbx_regexp_match_precompiled(value_str.data.str, regex))
1132 {
1133 errmsg = zbx_strdup(NULL, "value matches regular expression");
1134 }
1135 else
1136 ret = SUCCEED;
1137
1138 zbx_regexp_free(regex);
1139 out:
1140 zbx_variant_clear(&value_str);
1141
1142 if (FAIL == ret)
1143 {
1144 *error = zbx_dsprintf(*error, "cannot perform regular expression \"%s\" validation"
1145 " for value of type \"%s\": %s",
1146 params, zbx_variant_type_desc(value), errmsg);
1147 zbx_free(errmsg);
1148 }
1149
1150 return ret;
1151 }
1152
1153 /******************************************************************************
1154 * *
1155 * Function: item_preproc_get_error_from_json *
1156 * *
1157 * Purpose: checks for presence of error field in json data *
1158 * *
1159 * Parameters: value - [IN/OUT] the value to process *
1160 * params - [IN] the operation parameters *
1161 * error - [OUT] error message *
1162 * *
1163 * Return value: FAIL - preprocessing step error *
1164 * SUCCEED - preprocessing step succeeded, error may contain *
1165 * extracted error message *
1166 * *
1167 * Comments: This preprocessing step is used to check if the returned data *
1168 * contains explicit (API related) error message and sets it as *
1169 * error, while returning SUCCEED. *
1170 * *
1171 ******************************************************************************/
item_preproc_get_error_from_json(const zbx_variant_t * value,const char * params,char ** error)1172 static int item_preproc_get_error_from_json(const zbx_variant_t *value, const char *params, char **error)
1173 {
1174 zbx_variant_t value_str;
1175 int ret;
1176 struct zbx_json_parse jp;
1177
1178 zbx_variant_copy(&value_str, value);
1179
1180 if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
1181 {
1182 THIS_SHOULD_NEVER_HAPPEN;
1183 goto out;
1184 }
1185
1186 if (FAIL == zbx_json_open(value->data.str, &jp))
1187 goto out;
1188
1189 if (FAIL == (ret = zbx_jsonpath_query(&jp, params, error)))
1190 {
1191 *error = zbx_strdup(NULL, zbx_json_strerror());
1192 goto out;
1193 }
1194
1195 if (NULL != *error)
1196 {
1197 zbx_lrtrim(*error, ZBX_WHITESPACE);
1198 if ('\0' == **error)
1199 zbx_free(*error);
1200 else
1201 ret = FAIL;
1202 }
1203 out:
1204 zbx_variant_clear(&value_str);
1205
1206 return ret;
1207 }
1208
1209 /******************************************************************************
1210 * *
1211 * Function: item_preproc_get_error_from_xml *
1212 * *
1213 * Purpose: checks for presence of error field in XML data *
1214 * *
1215 * Parameters: value - [IN/OUT] the value to process *
1216 * params - [IN] the operation parameters *
1217 * error - [OUT] the error message *
1218 * *
1219 * Return value: FAIL - preprocessing step error *
1220 * SUCCEED - preprocessing step succeeded, error may contain *
1221 * extracted error message *
1222 * *
1223 * Comments: This preprocessing step is used to check if the returned data *
1224 * contains explicit (API related) error message and sets it as *
1225 * error, while returning SUCCEED. *
1226 * *
1227 ******************************************************************************/
item_preproc_get_error_from_xml(const zbx_variant_t * value,const char * params,char ** error)1228 static int item_preproc_get_error_from_xml(const zbx_variant_t *value, const char *params, char **error)
1229 {
1230 #ifndef HAVE_LIBXML2
1231 ZBX_UNUSED(value);
1232 ZBX_UNUSED(params);
1233 ZBX_UNUSED(error);
1234 *error = zbx_dsprintf(*error, "Zabbix was compiled without libxml2 support");
1235 return FAIL;
1236 #else
1237 zbx_variant_t value_str;
1238 int ret = SUCCEED, i;
1239 xmlDoc *doc = NULL;
1240 xmlXPathContext *xpathCtx = NULL;
1241 xmlXPathObject *xpathObj = NULL;
1242 xmlErrorPtr pErr;
1243 xmlBufferPtr xmlBufferLocal;
1244
1245 zbx_variant_copy(&value_str, value);
1246
1247 if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
1248 {
1249 THIS_SHOULD_NEVER_HAPPEN;
1250 goto out;
1251 }
1252
1253 if (NULL == (doc = xmlReadMemory(value_str.data.str, strlen(value_str.data.str), "noname.xml", NULL, 0)))
1254 goto out;
1255
1256 xpathCtx = xmlXPathNewContext(doc);
1257
1258 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)params, xpathCtx)))
1259 {
1260 pErr = xmlGetLastError();
1261 *error = zbx_dsprintf(*error, "cannot parse xpath \"%s\": %s", params, pErr->message);
1262 ret = FAIL;
1263 goto out;
1264 }
1265
1266 switch (xpathObj->type)
1267 {
1268 case XPATH_NODESET:
1269 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
1270 goto out;
1271
1272 xmlBufferLocal = xmlBufferCreate();
1273
1274 for (i = 0; i < xpathObj->nodesetval->nodeNr; i++)
1275 xmlNodeDump(xmlBufferLocal, doc, xpathObj->nodesetval->nodeTab[i], 0, 0);
1276
1277 *error = zbx_strdup(*error, (const char *)xmlBufferLocal->content);
1278 xmlBufferFree(xmlBufferLocal);
1279 break;
1280 case XPATH_STRING:
1281 *error = zbx_strdup(*error, (const char *)xpathObj->stringval);
1282 break;
1283 case XPATH_BOOLEAN:
1284 *error = zbx_dsprintf(*error, "%d", xpathObj->boolval);
1285 break;
1286 case XPATH_NUMBER:
1287 *error = zbx_dsprintf(*error, ZBX_FS_DBL, xpathObj->floatval);
1288 break;
1289 default:
1290 *error = zbx_strdup(*error, "Unknown error");
1291 break;
1292 }
1293
1294 zbx_lrtrim(*error, ZBX_WHITESPACE);
1295 if ('\0' == **error)
1296 zbx_free(*error);
1297 else
1298 ret = FAIL;
1299 out:
1300 zbx_variant_clear(&value_str);
1301
1302 if (NULL != xpathObj)
1303 xmlXPathFreeObject(xpathObj);
1304
1305 if (NULL != xpathCtx)
1306 xmlXPathFreeContext(xpathCtx);
1307
1308 if (NULL != doc)
1309 xmlFreeDoc(doc);
1310
1311 return ret;
1312 #endif
1313 }
1314
1315 /******************************************************************************
1316 * *
1317 * Function: item_preproc_get_error_from_regex *
1318 * *
1319 * Purpose: checks for presence of error pattern matching regular expression *
1320 * *
1321 * Parameters: value - [IN/OUT] the value to process *
1322 * params - [IN] the operation parameters *
1323 * error - [OUT] the error message *
1324 * *
1325 * Return value: FAIL - preprocessing step error *
1326 * SUCCEED - preprocessing step succeeded, error may contain *
1327 * extracted error message *
1328 * *
1329 * Comments: This preprocessing step is used to check if the returned data *
1330 * contains explicit (API related) error message and sets it as *
1331 * error, while returning SUCCEED. *
1332 * *
1333 ******************************************************************************/
item_preproc_get_error_from_regex(const zbx_variant_t * value,const char * params,char ** error)1334 static int item_preproc_get_error_from_regex(const zbx_variant_t *value, const char *params, char **error)
1335 {
1336 zbx_variant_t value_str;
1337 int ret;
1338 char pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *output;
1339
1340 zbx_variant_copy(&value_str, value);
1341
1342 if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
1343 {
1344 THIS_SHOULD_NEVER_HAPPEN;
1345 goto out;
1346 }
1347
1348 zbx_strlcpy(pattern, params, sizeof(pattern));
1349 if (NULL == (output = strchr(pattern, '\n')))
1350 {
1351 *error = zbx_strdup(*error, "cannot find second parameter");
1352 ret = FAIL;
1353 goto out;
1354 }
1355
1356 *output++ = '\0';
1357
1358 if (FAIL == zbx_mregexp_sub(value_str.data.str, pattern, output, error))
1359 {
1360 *error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", pattern);
1361 ret = FAIL;
1362 goto out;
1363 }
1364
1365 if (NULL != *error)
1366 {
1367 zbx_lrtrim(*error, ZBX_WHITESPACE);
1368 if ('\0' == **error)
1369 zbx_free(*error);
1370 else
1371 ret = FAIL;
1372 }
1373 out:
1374 zbx_variant_clear(&value_str);
1375
1376 return ret;
1377 }
1378
1379 /******************************************************************************
1380 * *
1381 * Function: item_preproc_throttle_value *
1382 * *
1383 * Purpose: throttles value by suppressing identical values *
1384 * *
1385 * Parameters: value - [IN/OUT] the value to process *
1386 * ts - [IN] the value timestamp *
1387 * history_value - [IN] historical data of item with delta *
1388 * preprocessing operation *
1389 * errmsg - [OUT] error message *
1390 * *
1391 * Return value: SUCCEED - the value was calculated successfully *
1392 * FAIL - otherwise *
1393 * *
1394 ******************************************************************************/
item_preproc_throttle_value(zbx_variant_t * value,const zbx_timespec_t * ts,zbx_variant_t * history_value,zbx_timespec_t * history_ts)1395 static int item_preproc_throttle_value(zbx_variant_t *value, const zbx_timespec_t *ts,
1396 zbx_variant_t *history_value, zbx_timespec_t *history_ts)
1397 {
1398 int ret;
1399
1400 ret = zbx_variant_compare(value, history_value);
1401
1402 zbx_variant_clear(history_value);
1403 zbx_variant_copy(history_value, value);
1404
1405 if (0 == ret)
1406 zbx_variant_clear(value);
1407 else
1408 *history_ts = *ts;
1409
1410 return SUCCEED;
1411 }
1412
1413 /******************************************************************************
1414 * *
1415 * Function: item_preproc_throttle_timed_value *
1416 * *
1417 * Purpose: throttles value by suppressing identical values *
1418 * *
1419 * Parameters: value - [IN/OUT] the value to process *
1420 * ts - [IN] the value timestamp *
1421 * params - [IN] the throttle period *
1422 * history_value - [IN] historical data of item with delta *
1423 * preprocessing operation *
1424 * errmsg - [OUT] error message *
1425 * *
1426 * Return value: SUCCEED - the value was calculated successfully *
1427 * FAIL - otherwise *
1428 * *
1429 ******************************************************************************/
item_preproc_throttle_timed_value(zbx_variant_t * value,const zbx_timespec_t * ts,const char * params,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** errmsg)1430 static int item_preproc_throttle_timed_value(zbx_variant_t *value, const zbx_timespec_t *ts, const char *params,
1431 zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **errmsg)
1432 {
1433 int ret, timeout, period = 0;
1434
1435 if (FAIL == is_time_suffix(params, &timeout, strlen(params)))
1436 {
1437 *errmsg = zbx_dsprintf(*errmsg, "invalid time period: %s", params);
1438 zbx_variant_clear(history_value);
1439 return FAIL;
1440 }
1441
1442 ret = zbx_variant_compare(value, history_value);
1443
1444 zbx_variant_clear(history_value);
1445 zbx_variant_copy(history_value, value);
1446
1447 if (ZBX_VARIANT_NONE != history_value->type)
1448 period = ts->sec - history_ts->sec;
1449
1450 if (0 == ret && period < timeout )
1451 zbx_variant_clear(value);
1452 else
1453 *history_ts = *ts;
1454
1455 return SUCCEED;
1456 }
1457
1458 /******************************************************************************
1459 * *
1460 * Function: item_preproc_script *
1461 * *
1462 * Purpose: executes script passed with params *
1463 * *
1464 * Parameters: value - [IN/OUT] the value to process *
1465 * params - [IN] the script to execute *
1466 * bytecode - [IN] precompiled bytecode, can be NULL *
1467 * errmsg - [OUT] error message *
1468 * *
1469 * Return value: SUCCEED - the value was calculated successfully *
1470 * FAIL - otherwise *
1471 * *
1472 ******************************************************************************/
item_preproc_script(zbx_variant_t * value,const char * params,zbx_variant_t * bytecode,char ** errmsg)1473 static int item_preproc_script(zbx_variant_t *value, const char *params, zbx_variant_t *bytecode, char **errmsg)
1474 {
1475 char *code, *output = NULL, *error = NULL;
1476 int size;
1477
1478 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1479 return FAIL;
1480
1481 if (SUCCEED != zbx_es_is_env_initialized(&es_engine))
1482 {
1483 if (SUCCEED != zbx_es_init_env(&es_engine, errmsg))
1484 return FAIL;
1485 }
1486
1487 if (ZBX_VARIANT_BIN != bytecode->type)
1488 {
1489 if (SUCCEED != zbx_es_compile(&es_engine, params, &code, &size, errmsg))
1490 goto fail;
1491
1492 zbx_variant_clear(bytecode);
1493 zbx_variant_set_bin(bytecode, zbx_variant_data_bin_create(code, size));
1494 zbx_free(code);
1495 }
1496
1497 size = zbx_variant_data_bin_get(bytecode->data.bin, (void **)&code);
1498
1499 if (SUCCEED == zbx_es_execute(&es_engine, params, code, size, value->data.str, &output, errmsg))
1500 {
1501 zbx_variant_clear(value);
1502
1503 if (NULL != output)
1504 zbx_variant_set_str(value, output);
1505
1506 return SUCCEED;
1507 }
1508 fail:
1509 if (SUCCEED == zbx_es_fatal_error(&es_engine))
1510 {
1511 if (SUCCEED != zbx_es_destroy_env(&es_engine, &error))
1512 {
1513 zabbix_log(LOG_LEVEL_WARNING,
1514 "Cannot destroy embedded scripting engine environment: %s", error);
1515 zbx_free(error);
1516 }
1517 }
1518
1519 return FAIL;
1520 }
1521
1522 /******************************************************************************
1523 * *
1524 * Function: item_preproc_prometheus_pattern *
1525 * *
1526 * Purpose: parse Prometheus format metrics *
1527 * *
1528 * Parameters: value - [IN/OUT] the value to process *
1529 * params - [IN] the operation parameters *
1530 * errmsg - [OUT] error message *
1531 * *
1532 * Return value: SUCCEED - the value was processed successfully *
1533 * FAIL - otherwise *
1534 * *
1535 ******************************************************************************/
item_preproc_prometheus_pattern(zbx_variant_t * value,const char * params,char ** errmsg)1536 static int item_preproc_prometheus_pattern(zbx_variant_t *value, const char *params, char **errmsg)
1537 {
1538 char pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *output, *value_out = NULL,
1539 *err = NULL;
1540
1541 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1542 return FAIL;
1543
1544 zbx_strlcpy(pattern, params, sizeof(pattern));
1545
1546 if (NULL == (output = strchr(pattern, '\n')))
1547 {
1548 *errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
1549 return FAIL;
1550 }
1551
1552 *output++ = '\0';
1553
1554 if (FAIL == zbx_prometheus_pattern(value->data.str, pattern, output, &value_out, &err))
1555 {
1556 *errmsg = zbx_dsprintf(*errmsg, "cannot apply Prometheus pattern: %s", err);
1557 zbx_free(err);
1558 return FAIL;
1559 }
1560
1561 zbx_variant_clear(value);
1562 zbx_variant_set_str(value, value_out);
1563
1564 return SUCCEED;
1565 }
1566
1567 /******************************************************************************
1568 * *
1569 * Function: item_preproc_prometheus_to_json *
1570 * *
1571 * Purpose: convert Prometheus format metrics to JSON format *
1572 * *
1573 * Parameters: value - [IN/OUT] the value to process *
1574 * params - [IN] the operation parameters *
1575 * errmsg - [OUT] error message *
1576 * *
1577 * Return value: SUCCEED - the value was processed successfully *
1578 * FAIL - otherwise *
1579 * *
1580 ******************************************************************************/
item_preproc_prometheus_to_json(zbx_variant_t * value,const char * params,char ** errmsg)1581 static int item_preproc_prometheus_to_json(zbx_variant_t *value, const char *params, char **errmsg)
1582 {
1583 char *value_out = NULL, *err = NULL;
1584
1585 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1586 return FAIL;
1587
1588 if (FAIL == zbx_prometheus_to_json(value->data.str, params, &value_out, &err))
1589 {
1590 *errmsg = zbx_dsprintf(*errmsg, "cannot convert Prometheus data to JSON: %s", err);
1591 zbx_free(err);
1592 return FAIL;
1593 }
1594
1595 zbx_variant_clear(value);
1596 zbx_variant_set_str(value, value_out);
1597
1598 return SUCCEED;
1599 }
1600
1601 /******************************************************************************
1602 * *
1603 * Function: item_preproc_csv_to_json_add_field *
1604 * *
1605 * Purpose: convert CSV format metrics to JSON format *
1606 * *
1607 * Parameters: json - [IN/OUT] json object *
1608 * names - [IN/OUT] column names *
1609 * field - [IN] field *
1610 * num - [IN] field number *
1611 * num_max - [IN] maximum number of fields *
1612 * header - [IN] header line option *
1613 * errmsg - [OUT] error message *
1614 * *
1615 * Return value: SUCCEED - the field was added successfully *
1616 * FAIL - otherwise *
1617 * *
1618 ******************************************************************************/
item_preproc_csv_to_json_add_field(struct zbx_json * json,char *** names,char * field,unsigned int num,unsigned int num_max,unsigned int header,char ** errmsg)1619 static int item_preproc_csv_to_json_add_field(struct zbx_json *json, char ***names, char *field, unsigned int num,
1620 unsigned int num_max, unsigned int header, char **errmsg)
1621 {
1622 char **fld_names = *names;
1623
1624 if (0 < num_max && num >= num_max && 1 == header)
1625 {
1626 *errmsg = zbx_strdup(*errmsg,
1627 "cannot convert CSV to JSON: data row contains more fields than header row");
1628 return FAIL;
1629 }
1630
1631 if (NULL == field)
1632 field = "";
1633
1634 if (0 == num_max && 1 == header)
1635 {
1636 unsigned int i;
1637
1638 for (i = 0; i < num; i++)
1639 {
1640 if (0 == strcmp(fld_names[i], field))
1641 {
1642 *errmsg = zbx_dsprintf(*errmsg,
1643 "cannot convert CSV to JSON: duplicated column name \"%s\"", field);
1644 return FAIL;
1645 }
1646 }
1647
1648 fld_names = zbx_realloc(fld_names, (num + 1) * sizeof(char*));
1649 fld_names[num] = zbx_strdup(NULL, field);
1650 *names = fld_names;
1651 }
1652 else
1653 {
1654 if (0 == num)
1655 zbx_json_addobject(json, NULL);
1656
1657 if (0 == header)
1658 {
1659 char num_buf[ZBX_MAX_UINT64_LEN];
1660
1661 zbx_snprintf(num_buf, ZBX_MAX_UINT64_LEN, "%u", num + 1);
1662 zbx_json_addstring(json, num_buf, field, ZBX_JSON_TYPE_STRING);
1663 }
1664 else
1665 zbx_json_addstring(json, fld_names[num], field, ZBX_JSON_TYPE_STRING);
1666
1667 if (ZBX_MAX_RECV_DATA_SIZE <= json->buffer_allocated)
1668 {
1669 *errmsg = zbx_strdup(*errmsg, "cannot convert CSV to JSON: input data is too large");
1670 return FAIL;
1671 }
1672 }
1673
1674 return SUCCEED;
1675 }
1676
1677 /******************************************************************************
1678 * *
1679 * Function: item_preproc_csv_to_json *
1680 * *
1681 * Purpose: convert CSV format metrics to JSON format *
1682 * *
1683 * Parameters: value - [IN/OUT] the value to process *
1684 * params - [IN] the operation parameters *
1685 * errmsg - [OUT] error message *
1686 * *
1687 * Return value: SUCCEED - the value was processed successfully *
1688 * FAIL - otherwise *
1689 * *
1690 ******************************************************************************/
item_preproc_csv_to_json(zbx_variant_t * value,const char * params,char ** errmsg)1691 static int item_preproc_csv_to_json(zbx_variant_t *value, const char *params, char **errmsg)
1692 {
1693 #define CSV_STATE_FIELD 0
1694 #define CSV_STATE_DELIM 1
1695 #define CSV_STATE_FIELD_QUOTED 2
1696
1697 unsigned int fld_num = 0, fld_num_max = 0, hdr_line, state = CSV_STATE_DELIM;
1698 char *field, *field_esc = NULL, **field_names = NULL, *data, *value_out = NULL,
1699 delim[ZBX_MAX_BYTES_IN_UTF8_CHAR], quote[ZBX_MAX_BYTES_IN_UTF8_CHAR];
1700 struct zbx_json json;
1701 size_t data_len, delim_sz = 1, quote_sz = 0, step;
1702 int ret = SUCCEED;
1703
1704 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1705 return FAIL;
1706
1707 delim[0] = ',';
1708 zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
1709 data = value->data.str;
1710 data_len = strlen(value->data.str);
1711
1712 #define CSV_SEP_LINE "sep="
1713 if (0 == zbx_strncasecmp(data, CSV_SEP_LINE, ZBX_CONST_STRLEN(CSV_SEP_LINE)))
1714 {
1715 char *p;
1716 size_t del_sz;
1717
1718 p = value->data.str + ZBX_CONST_STRLEN(CSV_SEP_LINE);
1719
1720 if (NULL == (field = strpbrk(p, "\r\n")))
1721 field = data + data_len;
1722
1723 if (0 < (del_sz = zbx_utf8_char_len(p)) && p + del_sz == field)
1724 {
1725 memcpy(delim, p, del_sz);
1726 delim_sz = del_sz;
1727
1728 if ('\0' == *field)
1729 data = field;
1730 else if ('\r' == *field)
1731 data = field + 2;
1732 else
1733 data = field + 1;
1734 }
1735 }
1736 #undef CSV_SEP_LINE
1737
1738 if ('\n' != *params)
1739 {
1740 if (NULL == (field = strchr(params, '\n')))
1741 {
1742 *errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
1743 return FAIL;
1744 }
1745
1746 if (0 == (delim_sz = zbx_utf8_char_len(params)) || params + delim_sz != field)
1747 {
1748 *errmsg = zbx_strdup(*errmsg, "invalid first parameter");
1749 return FAIL;
1750 }
1751
1752 memcpy(delim, params, delim_sz);
1753 params = field;
1754 }
1755
1756 if ('\n' != *(++params))
1757 {
1758 if (NULL == (field = strchr(params, '\n')))
1759 {
1760 *errmsg = zbx_strdup(*errmsg, "cannot find third parameter");
1761 return FAIL;
1762 }
1763
1764 if (0 == (quote_sz = zbx_utf8_char_len(params)) || params + quote_sz != field)
1765 {
1766 *errmsg = zbx_strdup(*errmsg, "invalid second parameter");
1767 return FAIL;
1768 }
1769
1770 memcpy(quote, params, quote_sz);
1771 params = field;
1772 }
1773
1774 hdr_line = ('1' == *(++params) ? 1 : 0);
1775
1776 if ('\0' == *data)
1777 goto out;
1778
1779 for (field = NULL; value->data.str + data_len >= data; data += step)
1780 {
1781 if (0 == (step = zbx_utf8_char_len(data)))
1782 {
1783 *errmsg = zbx_strdup(*errmsg, "cannot convert CSV to JSON: invalid UTF-8 character in value");
1784 ret = FAIL;
1785 goto out;
1786 }
1787
1788 if (CSV_STATE_FIELD_QUOTED != state)
1789 {
1790 if ('\r' == *data)
1791 {
1792 *data = '\0';
1793
1794 if ('\n' != *(++data) && '\0' != *data)
1795 {
1796 *errmsg = zbx_strdup(*errmsg, "cannot convert CSV to JSON: unsupported line "
1797 "break");
1798 ret = FAIL;
1799 goto out;
1800 }
1801 }
1802
1803 if ('\n' == *data || '\0' == *data)
1804 {
1805 if (CSV_STATE_FIELD == state || 1 == hdr_line || 0 != fld_num)
1806 {
1807 *data = '\0';
1808
1809 do
1810 {
1811 if (FAIL == (ret = item_preproc_csv_to_json_add_field(&json,
1812 &field_names, field, fld_num, fld_num_max, hdr_line,
1813 errmsg)))
1814 goto out;
1815
1816 field = NULL;
1817 zbx_free(field_esc);
1818 } while (++fld_num < fld_num_max && 1 == hdr_line);
1819
1820 if (fld_num > fld_num_max)
1821 fld_num_max = fld_num;
1822
1823 fld_num = 0;
1824 }
1825 else
1826 zbx_json_addobject(&json, NULL);
1827
1828 zbx_json_close(&json);
1829 state = CSV_STATE_DELIM;
1830 }
1831 else if (step == delim_sz && 0 == memcmp(data, delim, delim_sz))
1832 {
1833 *data = '\0';
1834
1835 if (FAIL == (ret = item_preproc_csv_to_json_add_field(&json,
1836 &field_names, field, fld_num, fld_num_max, hdr_line,
1837 errmsg)))
1838 goto out;
1839
1840 field = NULL;
1841 zbx_free(field_esc);
1842 fld_num++;
1843 state = CSV_STATE_DELIM;
1844 }
1845 else if (CSV_STATE_DELIM == state && step == quote_sz && 0 == memcmp(data, quote, quote_sz))
1846 {
1847 state = CSV_STATE_FIELD_QUOTED;
1848 }
1849 else if (CSV_STATE_FIELD != state)
1850 {
1851 field = data;
1852 state = CSV_STATE_FIELD;
1853 }
1854 }
1855 else if (step == quote_sz && 0 == memcmp(data, quote, quote_sz))
1856 {
1857 char *data_next = data + quote_sz;
1858 size_t char_sz;
1859
1860 if (0 == (char_sz = zbx_utf8_char_len(data_next)))
1861 continue; /* invalid UTF-8 */
1862
1863 if (char_sz == quote_sz && 0 == memcmp(data_next, quote, quote_sz))
1864 {
1865 if (NULL == field)
1866 field = data;
1867
1868 *data_next = '\0';
1869 field_esc = zbx_dsprintf(field_esc, "%s%s", ZBX_NULL2EMPTY_STR(field_esc), field);
1870 field = NULL;
1871 data = data_next;
1872 }
1873 else if ('\r' == *data_next || '\n' == *data_next || '\0' == *data_next ||
1874 (char_sz == delim_sz && 0 == memcmp(data_next, delim, delim_sz)))
1875 {
1876 state = CSV_STATE_FIELD;
1877 *data = '\0';
1878
1879 if (NULL != field_esc)
1880 {
1881 field_esc = zbx_dsprintf(field_esc, "%s%s", field_esc,
1882 ZBX_NULL2EMPTY_STR(field));
1883 field = field_esc;
1884 }
1885 }
1886 else
1887 {
1888 *errmsg = zbx_dsprintf(*errmsg, "cannot convert CSV to JSON: delimiter character or "
1889 "end of line are not detected after quoted field \"%.*s\"",
1890 (int)(data - field), field);
1891 ret = FAIL;
1892 goto out;
1893 }
1894 }
1895 else if (NULL == field)
1896 {
1897 field = data;
1898 }
1899 }
1900
1901 if (CSV_STATE_FIELD_QUOTED == state)
1902 {
1903 *errmsg = zbx_dsprintf(*errmsg, "cannot convert CSV to JSON: unclosed quoted field \"%s\"", field);
1904 ret = FAIL;
1905 }
1906
1907 out:
1908 if (SUCCEED == ret)
1909 {
1910 value_out = zbx_strdup(NULL, json.buffer);
1911 zbx_variant_clear(value);
1912 zbx_variant_set_str(value, value_out);
1913 }
1914
1915 if (1 == hdr_line)
1916 {
1917 if (0 == fld_num_max)
1918 fld_num_max = fld_num;
1919
1920 for (fld_num = 0; fld_num < fld_num_max; fld_num++)
1921 zbx_free(field_names[fld_num]);
1922
1923 zbx_free(field_names);
1924 }
1925
1926 zbx_free(field_esc);
1927 zbx_json_free(&json);
1928
1929 return ret;
1930 #undef CSV_STATE_FIELD
1931 #undef CSV_STATE_DELIM
1932 #undef CSV_STATE_FIELD_QUOTED
1933 }
1934
1935 /******************************************************************************
1936 * *
1937 * Function: item_preproc_xml_to_json *
1938 * *
1939 * Purpose: convert XML format value to JSON format *
1940 * *
1941 * Parameters: value - [IN/OUT] the value to process *
1942 * errmsg - [OUT] error message *
1943 * *
1944 * Return value: SUCCEED - the value was processed successfully *
1945 * FAIL - otherwise *
1946 * *
1947 ******************************************************************************/
item_preproc_xml_to_json(zbx_variant_t * value,char ** errmsg)1948 static int item_preproc_xml_to_json(zbx_variant_t *value, char **errmsg)
1949 {
1950 char *json = NULL;
1951
1952 if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
1953 return FAIL;
1954
1955 if (FAIL == zbx_xml_to_json(value->data.str, &json, errmsg))
1956 return FAIL;
1957
1958 zbx_variant_clear(value);
1959 zbx_variant_set_str(value, json);
1960
1961 return SUCCEED;
1962 }
1963
1964 /******************************************************************************
1965 * *
1966 * Function: item_preproc_str_replace *
1967 * *
1968 * Purpose: replace substrings in string *
1969 * *
1970 * Parameters: value - [IN/OUT] the value to process *
1971 * params - [IN] the operation parameters *
1972 * errmsg - [OUT] error message *
1973 * *
1974 * Return value: SUCCEED - the value was processed successfully *
1975 * FAIL - otherwise *
1976 * *
1977 ******************************************************************************/
item_preproc_str_replace(zbx_variant_t * value,const char * params,char ** errmsg)1978 static int item_preproc_str_replace(zbx_variant_t *value, const char *params, char **errmsg)
1979 {
1980 unsigned int len_search, len_replace;
1981 const char *ptr;
1982 char *new_string, search_str[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1],
1983 replace_str[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1];
1984
1985 if (NULL == (ptr = strchr(params, '\n')))
1986 {
1987 THIS_SHOULD_NEVER_HAPPEN;
1988 *errmsg = zbx_strdup(*errmsg, "cannot find second parameter");
1989 return FAIL;
1990 }
1991
1992 if (0 == (len_search = ptr - params))
1993 {
1994 *errmsg = zbx_strdup(*errmsg, "first parameter is expected");
1995 return FAIL;
1996 }
1997
1998 unescape_param(ZBX_PREPROC_STR_REPLACE, params, MIN(len_search, sizeof(search_str) - 1), search_str);
1999
2000 len_replace = strlen(ptr + 1);
2001 unescape_param(ZBX_PREPROC_STR_REPLACE, ptr + 1, MIN(len_replace, sizeof(replace_str) - 1), replace_str);
2002
2003 if (SUCCEED != item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
2004 {
2005 THIS_SHOULD_NEVER_HAPPEN;
2006 return FAIL;
2007 }
2008
2009 new_string = string_replace(value->data.str, search_str, replace_str);
2010 zbx_variant_clear(value);
2011 zbx_variant_set_str(value, new_string);
2012
2013 return SUCCEED;
2014 }
2015
2016 /******************************************************************************
2017 * *
2018 * Function: zbx_item_preproc *
2019 * *
2020 * Purpose: execute preprocessing operation *
2021 * *
2022 * Parameters: value_type - [IN] the item value type *
2023 * value - [IN/OUT] the value to process *
2024 * ts - [IN] the value timestamp *
2025 * op - [IN] the preprocessing operation to execute *
2026 * history_value - [IN/OUT] last historical data of items with *
2027 * delta type preprocessing operation *
2028 * error - [OUT] error message *
2029 * *
2030 * Return value: SUCCEED - the preprocessing step finished successfully *
2031 * FAIL - otherwise, error contains the error message *
2032 * *
2033 * Comments: When preprocessing step was executed successfully, but it must *
2034 * force an error (extract error steps), then success will be *
2035 * returned with error set. *
2036 * *
2037 ******************************************************************************/
zbx_item_preproc(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,const zbx_preproc_op_t * op,zbx_variant_t * history_value,zbx_timespec_t * history_ts,char ** error)2038 int zbx_item_preproc(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
2039 const zbx_preproc_op_t *op, zbx_variant_t *history_value, zbx_timespec_t *history_ts, char **error)
2040 {
2041 int ret;
2042
2043 switch (op->type)
2044 {
2045 case ZBX_PREPROC_MULTIPLIER:
2046 ret = item_preproc_multiplier(value_type, value, op->params, error);
2047 break;
2048 case ZBX_PREPROC_RTRIM:
2049 ret = item_preproc_rtrim(value, op->params, error);
2050 break;
2051 case ZBX_PREPROC_LTRIM:
2052 ret = item_preproc_ltrim(value, op->params, error);
2053 break;
2054 case ZBX_PREPROC_TRIM:
2055 ret = item_preproc_lrtrim(value, op->params, error);
2056 break;
2057 case ZBX_PREPROC_REGSUB:
2058 ret = item_preproc_regsub(value, op->params, error);
2059 break;
2060 case ZBX_PREPROC_BOOL2DEC:
2061 ret = item_preproc_bool2dec(value, error);
2062 break;
2063 case ZBX_PREPROC_OCT2DEC:
2064 ret = item_preproc_oct2dec(value, error);
2065 break;
2066 case ZBX_PREPROC_HEX2DEC:
2067 ret = item_preproc_hex2dec(value, error);
2068 break;
2069 case ZBX_PREPROC_DELTA_VALUE:
2070 ret = item_preproc_delta_value(value_type, value, ts, history_value, history_ts, error);
2071 break;
2072 case ZBX_PREPROC_DELTA_SPEED:
2073 ret = item_preproc_delta_speed(value_type, value, ts, history_value, history_ts, error);
2074 break;
2075 case ZBX_PREPROC_XPATH:
2076 ret = item_preproc_xpath(value, op->params, error);
2077 break;
2078 case ZBX_PREPROC_JSONPATH:
2079 ret = item_preproc_jsonpath(value, op->params, error);
2080 break;
2081 case ZBX_PREPROC_VALIDATE_RANGE:
2082 ret = item_preproc_validate_range(value_type, value, op->params, error);
2083 break;
2084 case ZBX_PREPROC_VALIDATE_REGEX:
2085 ret = item_preproc_validate_regex(value, op->params, error);
2086 break;
2087 case ZBX_PREPROC_VALIDATE_NOT_REGEX:
2088 ret = item_preproc_validate_not_regex(value, op->params, error);
2089 break;
2090 case ZBX_PREPROC_ERROR_FIELD_JSON:
2091 ret = item_preproc_get_error_from_json(value, op->params, error);
2092 break;
2093 case ZBX_PREPROC_ERROR_FIELD_XML:
2094 ret = item_preproc_get_error_from_xml(value, op->params, error);
2095 break;
2096 case ZBX_PREPROC_ERROR_FIELD_REGEX:
2097 ret = item_preproc_get_error_from_regex(value, op->params, error);
2098 break;
2099 case ZBX_PREPROC_THROTTLE_VALUE:
2100 ret = item_preproc_throttle_value(value, ts, history_value, history_ts);
2101 break;
2102 case ZBX_PREPROC_THROTTLE_TIMED_VALUE:
2103 ret = item_preproc_throttle_timed_value(value, ts, op->params, history_value, history_ts,
2104 error);
2105 break;
2106 case ZBX_PREPROC_SCRIPT:
2107 ret = item_preproc_script(value, op->params, history_value, error);
2108 break;
2109 case ZBX_PREPROC_PROMETHEUS_PATTERN:
2110 ret = item_preproc_prometheus_pattern(value, op->params, error);
2111 break;
2112 case ZBX_PREPROC_PROMETHEUS_TO_JSON:
2113 ret = item_preproc_prometheus_to_json(value, op->params, error);
2114 break;
2115 case ZBX_PREPROC_CSV_TO_JSON:
2116 ret = item_preproc_csv_to_json(value, op->params, error);
2117 break;
2118 case ZBX_PREPROC_STR_REPLACE:
2119 ret = item_preproc_str_replace(value, op->params, error);
2120 break;
2121 case ZBX_PREPROC_VALIDATE_NOT_SUPPORTED:
2122 ret = item_preproc_validate_notsupport(error);
2123 break;
2124 case ZBX_PREPROC_XML_TO_JSON:
2125 ret = item_preproc_xml_to_json(value, error);
2126 break;
2127 default:
2128 *error = zbx_dsprintf(*error, "unknown preprocessing operation");
2129 ret = FAIL;
2130 }
2131
2132 return ret;
2133 }
2134
2135 /******************************************************************************
2136 * *
2137 * Function: zbx_item_preproc_handle_error *
2138 * *
2139 * Purpose: apply 'on fail' preprocessing error handler *
2140 * *
2141 * Parameters: value - [IN/OUT] the value *
2142 * op - [IN] the preprocessing operation that produced *
2143 * the error *
2144 * error - [INT/OUT] error message *
2145 * *
2146 * Return value: SUCCEED - the preprocessing step result was overridden by *
2147 * error handler to successful result. *
2148 * FAIL - the preprocessing step must still fail, error might*
2149 * have been changed. *
2150 * *
2151 ******************************************************************************/
zbx_item_preproc_handle_error(zbx_variant_t * value,const zbx_preproc_op_t * op,char ** error)2152 int zbx_item_preproc_handle_error(zbx_variant_t *value, const zbx_preproc_op_t *op, char **error)
2153 {
2154 switch (op->error_handler)
2155 {
2156 case ZBX_PREPROC_FAIL_DISCARD_VALUE:
2157 zbx_variant_clear(value);
2158 zbx_free(*error);
2159 return SUCCEED;
2160 case ZBX_PREPROC_FAIL_SET_VALUE:
2161 zbx_variant_clear(value);
2162 zbx_variant_set_str(value, zbx_strdup(NULL, op->error_handler_params));
2163 zbx_free(*error);
2164 return SUCCEED;
2165 case ZBX_PREPROC_FAIL_SET_ERROR:
2166 *error = zbx_strdup(*error, op->error_handler_params);
2167 return FAIL;
2168 default:
2169 return FAIL;
2170 }
2171 }
2172
2173 /******************************************************************************
2174 * *
2175 * Function: zbx_item_preproc_test *
2176 * *
2177 * Purpose: test preprocessing steps *
2178 * *
2179 * Parameters: value_type - [IN] the item value type *
2180 * value - [IN/OUT] the value to process *
2181 * ts - [IN] the value timestamp *
2182 * steps - [IN] the preprocessing steps to execute *
2183 * steps_num - [IN] the number of preprocessing steps *
2184 * history_in - [IN] the preprocessing history *
2185 * history_out - [OUT] the new preprocessing history *
2186 * results - [OUT] the preprocessing step results *
2187 * results_num - [OUT] the number of step results *
2188 * error - [OUT] error message *
2189 * *
2190 * Return value: SUCCEED - the preprocessing steps finished successfully *
2191 * FAIL - otherwise, error contains the error message *
2192 * *
2193 ******************************************************************************/
zbx_item_preproc_test(unsigned char value_type,zbx_variant_t * value,const zbx_timespec_t * ts,zbx_preproc_op_t * steps,int steps_num,zbx_vector_ptr_t * history_in,zbx_vector_ptr_t * history_out,zbx_preproc_result_t * results,int * results_num,char ** error)2194 int zbx_item_preproc_test(unsigned char value_type, zbx_variant_t *value, const zbx_timespec_t *ts,
2195 zbx_preproc_op_t *steps, int steps_num, zbx_vector_ptr_t *history_in, zbx_vector_ptr_t *history_out,
2196 zbx_preproc_result_t *results, int *results_num, char **error)
2197 {
2198 int i, ret = SUCCEED;
2199
2200 for (i = 0; i < steps_num; i++)
2201 {
2202 zbx_preproc_op_t *op = &steps[i];
2203 zbx_variant_t history_value;
2204 zbx_timespec_t history_ts;
2205
2206 zbx_preproc_history_pop_value(history_in, i, &history_value, &history_ts);
2207
2208 if (FAIL == (ret = zbx_item_preproc(value_type, value, ts, op, &history_value, &history_ts, error)))
2209 {
2210 results[i].action = op->error_handler;
2211 results[i].error = zbx_strdup(NULL, *error);
2212 ret = zbx_item_preproc_handle_error(value, op, error);
2213 }
2214 else
2215 {
2216 results[i].action = ZBX_PREPROC_FAIL_DEFAULT;
2217 results[i].error = NULL;
2218 }
2219
2220 if (SUCCEED != ret)
2221 {
2222 zbx_variant_set_none(&results[i].value);
2223 zbx_variant_clear(&history_value);
2224 break;
2225 }
2226
2227 zbx_variant_copy(&results[i].value, value);
2228
2229 if (ZBX_VARIANT_NONE != history_value.type)
2230 {
2231 /* the value is byte copied to history_out vector and doesn't have to be cleared */
2232 zbx_preproc_history_add_value(history_out, i, &history_value, &history_ts);
2233 }
2234
2235 if (ZBX_VARIANT_NONE == value->type)
2236 break;
2237 }
2238
2239 *results_num = (i == steps_num ? i : i + 1);
2240
2241 return ret;
2242 }
2243
2244 #ifdef HAVE_TESTS
2245 # include "../../../tests/zabbix_server/preprocessor/item_preproc_test.c"
2246 #endif
2247