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 "zbxicmpping.h"
21 #include "threads.h"
22 #include "comms.h"
23 #include "zbxexec.h"
24 #include "log.h"
25
26 extern char *CONFIG_SOURCE_IP;
27 extern char *CONFIG_FPING_LOCATION;
28 #ifdef HAVE_IPV6
29 extern char *CONFIG_FPING6_LOCATION;
30 #endif
31 extern char *CONFIG_TMPDIR;
32
33 /* old official fping (2.4b2_to_ipv6) did not support source IP address */
34 /* old patched versions (2.4b2_to_ipv6) provided either -I or -S options */
35 /* since fping 3.x it provides -I option for binding to an interface and -S option for source IP address */
36
37 static unsigned char source_ip_checked;
38 static const char *source_ip_option;
39 #ifdef HAVE_IPV6
40 static unsigned char source_ip6_checked;
41 static const char *source_ip6_option;
42 #endif
43
44 #define FPING_UNINITIALIZED_VALUE -2
45 static int packet_interval;
46 #ifdef HAVE_IPV6
47 static int packet_interval6;
48 static int fping_ipv6_supported;
49 #endif
50
51 #define FPING_CHECK_EXPIRED 3600 /* seconds, expire detected fping options every hour */
52 static time_t fping_check_reset_at; /* time of the last fping options expiration */
53
get_source_ip_option(const char * fping,const char ** option,unsigned char * checked)54 static void get_source_ip_option(const char *fping, const char **option, unsigned char *checked)
55 {
56 FILE *f;
57 char *p, tmp[MAX_STRING_LEN];
58
59 zbx_snprintf(tmp, sizeof(tmp), "%s -h 2>&1", fping);
60
61 if (NULL == (f = popen(tmp, "r")))
62 return;
63
64 while (NULL != fgets(tmp, sizeof(tmp), f))
65 {
66 for (p = tmp; isspace(*p); p++)
67 ;
68
69 if ('-' == p[0] && 'I' == p[1] && (isspace(p[2]) || ',' == p[2]))
70 {
71 *option = "-I";
72 continue;
73 }
74
75 if ('-' == p[0] && 'S' == p[1] && (isspace(p[2]) || ',' == p[2]))
76 {
77 *option = "-S";
78 break;
79 }
80 }
81
82 pclose(f);
83
84 *checked = 1;
85 }
86
87 /******************************************************************************
88 * *
89 * Function: get_interval_option *
90 * *
91 * Purpose: detect minimal possible fping packet interval *
92 * *
93 * Parameters: fping - [IN] the the location of fping program *
94 * dst - [IN] the the ip address for test *
95 * value - [OUT] interval between sending ping packets *
96 * (in millisec) *
97 * error - [OUT] error string if function fails *
98 * max_error_len - [IN] length of error buffer *
99 * *
100 * Return value: SUCCEED if processed successfully or FAIL otherwise *
101 * *
102 * Comments: supported minimum interval (in milliseconds) in different fping *
103 * versions: *
104 * +------------------+--------------------------+---------+ *
105 * | version X | as root/non-root/without | Default | *
106 * | | "safe limits" | | *
107 * +------------------+--------------------------+---------+ *
108 * | X < 3.14 | 1 / 10 / - | 25 | *
109 * | 3.14 <= X < 4.0 | 0 / 1 / - | 25 | *
110 * | 4.0 <= X | 0 / 0 / 1 | 10 | *
111 * +------------------+--------------------------+---------+ *
112 * Note! "Safe limits" is compile-time option introduced in *
113 * fping 4.0. Distribution packages ship fping binary without *
114 * "safe limits". *
115 * *
116 ******************************************************************************/
get_interval_option(const char * fping,const char * dst,int * value,char * error,size_t max_error_len)117 static int get_interval_option(const char *fping, const char *dst, int *value, char *error, size_t max_error_len)
118 {
119 char *out = NULL;
120 unsigned int intervals[] = {0, 1, 10};
121 size_t i;
122 int ret = FAIL;
123
124 for (i = 0; i < ARRSIZE(intervals); i++)
125 {
126 int ret_exec;
127 char tmp[MAX_STRING_LEN], err[255];
128 const char *p;
129
130 zabbix_log(LOG_LEVEL_DEBUG, "testing fping interval %u ms", intervals[i]);
131
132 zbx_snprintf(tmp, sizeof(tmp), "%s -c1 -t50 -i%u %s", fping, intervals[i], dst);
133
134 zbx_free(out);
135
136 /* call fping, ignore its exit code but mind execution failures */
137 if (TIMEOUT_ERROR == (ret_exec = zbx_execute(tmp, &out, err, sizeof(err), 1,
138 ZBX_EXIT_CODE_CHECKS_DISABLED)))
139 {
140 zbx_snprintf(error, max_error_len, "Timeout while executing \"%s\"", tmp);
141 goto out;
142 }
143
144 if (FAIL == ret_exec)
145 {
146 zbx_snprintf(error, max_error_len, "Cannot execute \"%s\": %s", tmp, err);
147 goto out;
148 }
149
150 /* First, check the output for suggested interval option, e. g.: */
151 /* */
152 /* /usr/sbin/fping: these options are too risky for mere mortals. */
153 /* /usr/sbin/fping: You need i >= 1, p >= 20, r < 20, and t >= 50 */
154
155 #define FPING_YOU_NEED_PREFIX "You need i >= "
156
157 if (NULL != (p = strstr(out, FPING_YOU_NEED_PREFIX)))
158 {
159 p += ZBX_CONST_STRLEN(FPING_YOU_NEED_PREFIX);
160
161 *value = atoi(p);
162 ret = SUCCEED;
163
164 goto out;
165 }
166
167 #undef FPING_YOU_NEED_PREFIX
168
169 /* in fping 3.16 they changed "You need i >=" to "You need -i >=" */
170
171 #define FPING_YOU_NEED_PREFIX "You need -i >= "
172
173 if (NULL != (p = strstr(out, FPING_YOU_NEED_PREFIX)))
174 {
175 p += ZBX_CONST_STRLEN(FPING_YOU_NEED_PREFIX);
176
177 *value = atoi(p);
178 ret = SUCCEED;
179
180 goto out;
181 }
182
183 #undef FPING_YOU_NEED_PREFIX
184
185 /* if we get dst in the beginning of the output, the used interval is allowed, */
186 /* unless we hit the help message which is always bigger than 1 Kb */
187 if (ZBX_KIBIBYTE > strlen(out))
188 {
189 /* skip white spaces */
190 for (p = out; '\0' != *p && isspace(*p); p++)
191 ;
192
193 if (strlen(p) >= strlen(dst) && 0 == strncmp(p, dst, strlen(dst)))
194 {
195 *value = intervals[i];
196 ret = SUCCEED;
197
198 goto out;
199 }
200
201 /* check if we hit the error message */
202 if (NULL != (p = strstr(out, " as root")))
203 {
204 zbx_rtrim(out, "\n");
205 zbx_strlcpy(error, out, max_error_len);
206 goto out;
207 }
208 }
209 }
210
211 /* if we are here we have probably hit the usage or error message, let's collect it if it's error message */
212
213 if (ZBX_KIBIBYTE > strlen(out) && 0 != strlen(out))
214 {
215 zbx_rtrim(out, "\n");
216 zbx_strlcpy(error, out, max_error_len);
217 }
218 else
219 zbx_snprintf(error, max_error_len, "Cannot detect the minimum interval of %s", fping);
220 out:
221 zbx_free(out);
222
223 return ret;
224 }
225
226 #ifdef HAVE_IPV6
227 /******************************************************************************
228 * *
229 * Function: get_ipv6_support *
230 * *
231 * Purpose: check fping supports IPv6 *
232 * *
233 * Parameters: fping - [IN] the the location of fping program *
234 * dst - [IN] the the ip address for test *
235 * *
236 * Return value: SUCCEED - IPv6 is supported *
237 * FAIL - IPv6 is not supported *
238 * *
239 ******************************************************************************/
get_ipv6_support(const char * fping,const char * dst)240 static int get_ipv6_support(const char * fping, const char *dst)
241 {
242 int ret;
243 char tmp[MAX_STRING_LEN], error[255], *out = NULL;
244
245 zbx_snprintf(tmp, sizeof(tmp), "%s -6 -c1 -t50 %s", fping, dst);
246
247 if ((SUCCEED == (ret = zbx_execute(tmp, &out, error, sizeof(error), 1, ZBX_EXIT_CODE_CHECKS_DISABLED)) &&
248 ZBX_KIBIBYTE > strlen(out) && NULL != strstr(out, dst)) || TIMEOUT_ERROR == ret)
249 {
250 ret = SUCCEED;
251 }
252 else
253 {
254 ret = FAIL;
255 }
256
257 zbx_free(out);
258
259 return ret;
260
261 }
262 #endif /* HAVE_IPV6 */
263
process_ping(ZBX_FPING_HOST * hosts,int hosts_count,int count,int interval,int size,int timeout,char * error,size_t max_error_len)264 static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int interval, int size, int timeout,
265 char *error, size_t max_error_len)
266 {
267 const char *__function_name = "process_ping";
268 const int response_time_chars_max = 20;
269
270 FILE *f;
271 char params[70];
272 char filename[MAX_STRING_LEN];
273 char *tmp = NULL;
274 size_t tmp_size;
275 size_t offset;
276 double sec;
277 int i, ret = NOTSUPPORTED, index;
278
279 #ifdef HAVE_IPV6
280 int family;
281 char params6[70];
282 size_t offset6;
283 char fping_existence = 0;
284 #define FPING_EXISTS 0x1
285 #define FPING6_EXISTS 0x2
286
287 #endif /* HAVE_IPV6 */
288
289 assert(hosts);
290
291 zabbix_log(LOG_LEVEL_DEBUG, "In %s() hosts_count:%d", __function_name, hosts_count);
292
293 /* expire detected options once in a while */
294 if ((time(NULL) - fping_check_reset_at) > FPING_CHECK_EXPIRED)
295 {
296 fping_check_reset_at = time(NULL);
297
298 source_ip_checked = 0;
299 packet_interval = FPING_UNINITIALIZED_VALUE;
300 #ifdef HAVE_IPV6
301 source_ip6_checked = 0;
302 packet_interval6 = FPING_UNINITIALIZED_VALUE;
303 fping_ipv6_supported = FPING_UNINITIALIZED_VALUE;
304 #endif
305 }
306
307 tmp_size = (size_t)(MAX_STRING_LEN + count * response_time_chars_max);
308 tmp = zbx_malloc(tmp, tmp_size);
309
310 if (-1 == access(CONFIG_FPING_LOCATION, X_OK))
311 {
312 #if !defined(HAVE_IPV6)
313 zbx_snprintf(error, max_error_len, "%s: %s", CONFIG_FPING_LOCATION, zbx_strerror(errno));
314 goto out;
315 #endif
316 }
317 else
318 {
319 #ifdef HAVE_IPV6
320 fping_existence |= FPING_EXISTS;
321 #else
322 if (NULL != CONFIG_SOURCE_IP)
323 {
324 if (FAIL == is_ip4(CONFIG_SOURCE_IP)) /* we do not have IPv4 family address in CONFIG_SOURCE_IP */
325 {
326 zbx_snprintf(error, max_error_len,
327 "You should enable IPv6 support to use IPv6 family address for SourceIP '%s'.", CONFIG_SOURCE_IP);
328 goto out;
329 }
330 }
331 #endif
332 }
333
334 #ifdef HAVE_IPV6
335 if (-1 == access(CONFIG_FPING6_LOCATION, X_OK))
336 {
337 if (0 == (fping_existence & FPING_EXISTS))
338 {
339 zbx_snprintf(error, max_error_len, "At least one of '%s', '%s' must exist. Both are missing in the system.",
340 CONFIG_FPING_LOCATION,
341 CONFIG_FPING6_LOCATION);
342 goto out;
343 }
344 }
345 else
346 fping_existence |= FPING6_EXISTS;
347 #endif /* HAVE_IPV6 */
348
349 offset = zbx_snprintf(params, sizeof(params), "-C%d", count);
350 if (0 != interval)
351 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -p%d", interval);
352 if (0 != size)
353 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -b%d", size);
354 if (0 != timeout)
355 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -t%d", timeout);
356
357 #ifdef HAVE_IPV6
358 strscpy(params6, params);
359 offset6 = offset;
360
361 if (0 != (fping_existence & FPING_EXISTS) && 0 != hosts_count)
362 {
363 if (FPING_UNINITIALIZED_VALUE == packet_interval)
364 {
365 if (SUCCEED != get_interval_option(CONFIG_FPING_LOCATION, hosts[0].addr, &packet_interval,
366 error, max_error_len))
367 {
368 goto out;
369 }
370
371 zabbix_log(LOG_LEVEL_DEBUG, "detected minimum supported fping interval (-i): %d",
372 packet_interval);
373 }
374
375 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -i%d", packet_interval);
376 }
377
378 if (0 != (fping_existence & FPING6_EXISTS) && 0 != hosts_count)
379 {
380 if (FPING_UNINITIALIZED_VALUE == packet_interval6)
381 {
382 if (SUCCEED != get_interval_option(CONFIG_FPING6_LOCATION, hosts[0].addr, &packet_interval6,
383 error, max_error_len))
384 {
385 goto out;
386 }
387
388 zabbix_log(LOG_LEVEL_DEBUG, "detected minimum supported fping6 interval (-i): %d",
389 packet_interval6);
390 }
391
392 offset6 += zbx_snprintf(params6 + offset6, sizeof(params6) - offset6, " -i%d", packet_interval6);
393 }
394 #else
395 if (0 != hosts_count)
396 {
397 if (FPING_UNINITIALIZED_VALUE == packet_interval)
398 {
399 if (SUCCEED != get_interval_option(CONFIG_FPING_LOCATION, hosts[0].addr, &packet_interval,
400 error, max_error_len))
401 {
402 goto out;
403 }
404
405 zabbix_log(LOG_LEVEL_DEBUG, "detected minimum supported fping interval (-i): %d",
406 packet_interval);
407 }
408
409 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -i%d", packet_interval);
410 }
411 #endif /* HAVE_IPV6 */
412
413 if (NULL != CONFIG_SOURCE_IP)
414 {
415 #ifdef HAVE_IPV6
416 if (0 != (fping_existence & FPING_EXISTS))
417 {
418 if (0 == source_ip_checked)
419 {
420 get_source_ip_option(CONFIG_FPING_LOCATION, &source_ip_option, &source_ip_checked);
421
422 zabbix_log(LOG_LEVEL_DEBUG, "detected fping source IP option: \"%s\"",
423 ZBX_NULL2EMPTY_STR(source_ip_option));
424 }
425
426 if (NULL != source_ip_option)
427 zbx_snprintf(params + offset, sizeof(params) - offset,
428 " %s%s", source_ip_option, CONFIG_SOURCE_IP);
429 }
430
431 if (0 != (fping_existence & FPING6_EXISTS))
432 {
433 if (0 == source_ip6_checked)
434 {
435 get_source_ip_option(CONFIG_FPING6_LOCATION, &source_ip6_option, &source_ip6_checked);
436
437 zabbix_log(LOG_LEVEL_DEBUG, "detected fping6 source IP option: \"%s\"",
438 ZBX_NULL2EMPTY_STR(source_ip6_option));
439 }
440
441 if (NULL != source_ip6_option)
442 zbx_snprintf(params6 + offset6, sizeof(params6) - offset6,
443 " %s%s", source_ip6_option, CONFIG_SOURCE_IP);
444 }
445 #else
446 if (0 == source_ip_checked)
447 {
448 get_source_ip_option(CONFIG_FPING_LOCATION, &source_ip_option, &source_ip_checked);
449
450 zabbix_log(LOG_LEVEL_DEBUG, "detected fping source IP option: \"%s\"",
451 ZBX_NULL2EMPTY_STR(source_ip_option));
452 }
453
454 if (NULL != source_ip_option)
455 zbx_snprintf(params + offset, sizeof(params) - offset,
456 " %s%s", source_ip_option, CONFIG_SOURCE_IP);
457 #endif /* HAVE_IPV6 */
458 }
459
460 zbx_snprintf(filename, sizeof(filename), "%s/%s_%li.pinger", CONFIG_TMPDIR, progname, zbx_get_thread_id());
461
462 #ifdef HAVE_IPV6
463 if (NULL != CONFIG_SOURCE_IP)
464 {
465 if (SUCCEED != get_address_family(CONFIG_SOURCE_IP, &family, error, (int)max_error_len))
466 goto out;
467
468 if (family == PF_INET)
469 {
470 if (0 == (fping_existence & FPING_EXISTS))
471 {
472 zbx_snprintf(error, max_error_len, "File '%s' cannot be found in the system.",
473 CONFIG_FPING_LOCATION);
474 goto out;
475 }
476
477 zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename);
478 }
479 else
480 {
481 if (0 == (fping_existence & FPING6_EXISTS))
482 {
483 zbx_snprintf(error, max_error_len, "File '%s' cannot be found in the system.",
484 CONFIG_FPING6_LOCATION);
485 goto out;
486 }
487
488 zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING6_LOCATION, params6, filename);
489 }
490 }
491 else
492 {
493 offset = 0;
494
495 if (0 != (fping_existence & FPING_EXISTS))
496 {
497 if (FPING_UNINITIALIZED_VALUE == fping_ipv6_supported)
498 {
499 fping_ipv6_supported = get_ipv6_support(CONFIG_FPING_LOCATION,hosts[0].addr);
500
501 zabbix_log(LOG_LEVEL_DEBUG, "detected fping IPv6 support: \"%s\"",
502 SUCCEED == fping_ipv6_supported ? "yes" : "no");
503 }
504
505 offset += zbx_snprintf(tmp + offset, tmp_size - offset,
506 "%s %s 2>&1 <%s;", CONFIG_FPING_LOCATION, params, filename);
507 }
508
509 if (0 != (fping_existence & FPING6_EXISTS) && SUCCEED != fping_ipv6_supported)
510 {
511 zbx_snprintf(tmp + offset, tmp_size - offset,
512 "%s %s 2>&1 <%s;", CONFIG_FPING6_LOCATION, params6, filename);
513 }
514 }
515 #else
516 zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename);
517 #endif /* HAVE_IPV6 */
518
519 if (NULL == (f = fopen(filename, "w")))
520 {
521 zbx_snprintf(error, max_error_len, "%s: %s", filename, zbx_strerror(errno));
522 goto out;
523 }
524
525 zabbix_log(LOG_LEVEL_DEBUG, "%s", filename);
526
527 for (i = 0; i < hosts_count; i++)
528 {
529 zabbix_log(LOG_LEVEL_DEBUG, " %s", hosts[i].addr);
530 fprintf(f, "%s\n", hosts[i].addr);
531 }
532
533 fclose(f);
534
535 zabbix_log(LOG_LEVEL_DEBUG, "%s", tmp);
536
537 if (NULL == (f = popen(tmp, "r")))
538 {
539 zbx_snprintf(error, max_error_len, "%s: %s", tmp, zbx_strerror(errno));
540
541 unlink(filename);
542
543 goto out;
544 }
545
546 if (NULL == fgets(tmp, (int)tmp_size, f))
547 {
548 zbx_snprintf(tmp, tmp_size, "no output");
549 }
550 else
551 {
552 for (i = 0; i < hosts_count; i++)
553 {
554 hosts[i].status = (char *)zbx_malloc(NULL, (size_t)count);
555 memset(hosts[i].status, 0, (size_t)count);
556 }
557
558 do
559 {
560 ZBX_FPING_HOST *host = NULL;
561 char *c;
562
563 zbx_rtrim(tmp, "\n");
564 zabbix_log(LOG_LEVEL_DEBUG, "read line [%s]", tmp);
565
566 if (NULL != (c = strchr(tmp, ' ')))
567 {
568 *c = '\0';
569
570 for (i = 0; i < hosts_count; i++)
571 {
572 if (0 == strcmp(tmp, hosts[i].addr))
573 {
574 host = &hosts[i];
575 break;
576 }
577 }
578
579 *c = ' ';
580 }
581
582 if (NULL == host)
583 continue;
584
585 if (NULL == (c = strstr(tmp, " : ")))
586 continue;
587
588 /* when NIC bonding is used, there are also lines like */
589 /* 192.168.1.2 : duplicate for [0], 96 bytes, 0.19 ms */
590
591 if (NULL != strstr(tmp, "duplicate for"))
592 continue;
593
594 c += 3;
595
596 /* There were two issues with processing only the fping's final status line: */
597 /* 1) pinging broadcast addresses could have resulted in responses from */
598 /* different hosts, which were counted as the target host responses; */
599 /* 2) there is a bug in fping (v3.8 at least) where pinging broadcast */
600 /* address will result in no individual responses, but the final */
601 /* status line might contain a bogus value. */
602 /* Because of the above issues we must monitor the individual responses */
603 /* and mark the valid ones. */
604 if ('[' == *c)
605 {
606 /* Fping appends response source address in format '[<- 10.3.0.10]' */
607 /* if it does not match the target address. Ignore such responses. */
608 if (NULL != strstr(c + 1, "[<-"))
609 continue;
610
611 /* get the index of individual ping response */
612 index = atoi(c + 1);
613
614 if (0 > index || index >= count)
615 continue;
616
617 /* since 5.0 Fping outputs individual failed packages in additional to successful: */
618 /* */
619 /* fping -C3 -i0 7.7.7.7 8.8.8.8 */
620 /* 8.8.8.8 : [0], 64 bytes, 9.37 ms (9.37 avg, 0% loss) */
621 /* 7.7.7.7 : [0], timed out (NaN avg, 100% loss) */
622 /* 8.8.8.8 : [1], 64 bytes, 8.72 ms (9.05 avg, 0% loss) */
623 /* 7.7.7.7 : [1], timed out (NaN avg, 100% loss) */
624 /* 8.8.8.8 : [2], 64 bytes, 7.28 ms (8.46 avg, 0% loss) */
625 /* 7.7.7.7 : [2], timed out (NaN avg, 100% loss) */
626 /* */
627 /* 7.7.7.7 : - - - */
628 /* 8.8.8.8 : 9.37 8.72 7.28 */
629 /* */
630 /* Judging by Fping source code we can disregard lines reporting "timed out". */
631
632 if (NULL != strstr(c + 2, " timed out "))
633 continue;
634
635 host->status[index] = 1;
636
637 continue;
638 }
639
640 /* process status line for a host */
641 index = 0;
642 do
643 {
644 if (1 == host->status[index])
645 {
646 sec = atof(c) / 1000; /* convert ms to seconds */
647
648 if (0 == host->rcv || host->min > sec)
649 host->min = sec;
650 if (0 == host->rcv || host->max < sec)
651 host->max = sec;
652 host->sum += sec;
653 host->rcv++;
654 }
655 }
656 while (++index < count && NULL != (c = strchr(c + 1, ' ')));
657
658 host->cnt += count;
659 #ifdef HAVE_IPV6
660 if (host->cnt == count && NULL == CONFIG_SOURCE_IP &&
661 0 != (fping_existence & FPING_EXISTS) &&
662 0 != (fping_existence & FPING6_EXISTS))
663 {
664 memset(host->status, 0, (size_t)count); /* reset response statuses for IPv6 */
665 }
666 #endif
667 ret = SUCCEED;
668 }
669 while (NULL != fgets(tmp, (int)tmp_size, f));
670
671 for (i = 0; i < hosts_count; i++)
672 zbx_free(hosts[i].status);
673 }
674 pclose(f);
675
676 unlink(filename);
677
678 if (NOTSUPPORTED == ret)
679 zbx_snprintf(error, max_error_len, "fping failed: %s", tmp);
680
681 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
682 out:
683 zbx_free(tmp);
684
685 return ret;
686 }
687
688 /******************************************************************************
689 * *
690 * Function: zbx_ping *
691 * *
692 * Purpose: ping hosts listed in the host files *
693 * *
694 * hosts_count - [IN] number of target hosts *
695 * count - [IN] number of pings to send to each target *
696 * (fping option -C) *
697 * period - [IN] interval between ping packets to one *
698 * target, in milliseconds *
699 * (fping option -p) *
700 * size - [IN] amount of ping data to send, in bytes *
701 * (fping option -b) *
702 * timeout - [IN] individual target initial timeout except *
703 * when count > 1, where it's the -p period *
704 * (fping option -t) *
705 * error - [OUT] error string if function fails *
706 * max_error_len - [IN] length of error buffer *
707 * *
708 * Return value: SUCCEED - successfully processed hosts *
709 * NOTSUPPORTED - otherwise *
710 * *
711 * Author: Alexei Vladishev *
712 * *
713 * Comments: use external binary 'fping' to avoid superuser privileges *
714 * *
715 ******************************************************************************/
zbx_ping(ZBX_FPING_HOST * hosts,int hosts_count,int count,int period,int size,int timeout,char * error,size_t max_error_len)716 int zbx_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int period, int size, int timeout,
717 char *error, size_t max_error_len)
718 {
719 const char *__function_name = "zbx_ping";
720
721 int ret;
722
723 zabbix_log(LOG_LEVEL_DEBUG, "In %s() hosts_count:%d", __function_name, hosts_count);
724
725 if (NOTSUPPORTED == (ret = process_ping(hosts, hosts_count, count, period, size, timeout, error, max_error_len)))
726 zabbix_log(LOG_LEVEL_ERR, "%s", error);
727
728 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
729
730 return ret;
731 }
732