summaryrefslogtreecommitdiffstats
path: root/plugins-root/check_icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root/check_icmp.c')
-rw-r--r--plugins-root/check_icmp.c684
1 files changed, 579 insertions, 105 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index 1d47e9f..303241d 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -43,7 +43,7 @@ const char *copyright = "2005-2008";
43const char *email = "devel@monitoring-plugins.org"; 43const char *email = "devel@monitoring-plugins.org";
44 44
45/** Monitoring Plugins basic includes */ 45/** Monitoring Plugins basic includes */
46#include "common.h" 46#include "../plugins/common.h"
47#include "netutils.h" 47#include "netutils.h"
48#include "utils.h" 48#include "utils.h"
49 49
@@ -109,18 +109,35 @@ typedef struct rta_host {
109 unsigned char icmp_type, icmp_code; /* type and code from errors */ 109 unsigned char icmp_type, icmp_code; /* type and code from errors */
110 unsigned short flags; /* control/status flags */ 110 unsigned short flags; /* control/status flags */
111 double rta; /* measured RTA */ 111 double rta; /* measured RTA */
112 int rta_status; // check result for RTA checks
112 double rtmax; /* max rtt */ 113 double rtmax; /* max rtt */
113 double rtmin; /* min rtt */ 114 double rtmin; /* min rtt */
115 double jitter; /* measured jitter */
116 int jitter_status; // check result for Jitter checks
117 double jitter_max; /* jitter rtt maximum */
118 double jitter_min; /* jitter rtt minimum */
119 double EffectiveLatency;
120 double mos; /* Mean opnion score */
121 int mos_status; // check result for MOS checks
122 double score; /* score */
123 int score_status; // check result for score checks
124 u_int last_tdiff;
125 u_int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
114 unsigned char pl; /* measured packet loss */ 126 unsigned char pl; /* measured packet loss */
127 int pl_status; // check result for packet loss checks
115 struct rta_host *next; /* linked list */ 128 struct rta_host *next; /* linked list */
129 int order_status; // check result for packet order checks
116} rta_host; 130} rta_host;
117 131
118#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */ 132#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */
119 133
120/* threshold structure. all values are maximum allowed, exclusive */ 134/* threshold structure. all values are maximum allowed, exclusive */
121typedef struct threshold { 135typedef struct threshold {
122 unsigned char pl; /* max allowed packet loss in percent */ 136 unsigned char pl; /* max allowed packet loss in percent */
123 unsigned int rta; /* roundtrip time average, microseconds */ 137 unsigned int rta; /* roundtrip time average, microseconds */
138 double jitter; /* jitter time average, microseconds */
139 double mos; /* MOS */
140 double score; /* Score */
124} threshold; 141} threshold;
125 142
126/* the data structure */ 143/* the data structure */
@@ -159,6 +176,16 @@ typedef union icmp_packet {
159#define MODE_ALL 2 176#define MODE_ALL 2
160#define MODE_ICMP 3 177#define MODE_ICMP 3
161 178
179enum enum_threshold_mode {
180 const_rta_mode,
181 const_packet_loss_mode,
182 const_jitter_mode,
183 const_mos_mode,
184 const_score_mode
185};
186
187typedef enum enum_threshold_mode threshold_mode;
188
162/* the different ping types we can do 189/* the different ping types we can do
163 * TODO: investigate ARP ping as well */ 190 * TODO: investigate ARP ping as well */
164#define HAVE_ICMP 1 191#define HAVE_ICMP 1
@@ -188,6 +215,8 @@ static int wait_for_reply(int, u_int);
188static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*); 215static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*);
189static int send_icmp_ping(int, struct rta_host *); 216static int send_icmp_ping(int, struct rta_host *);
190static int get_threshold(char *str, threshold *th); 217static int get_threshold(char *str, threshold *th);
218static bool get_threshold2(char *str, size_t length, threshold *, threshold *, threshold_mode mode);
219static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode);
191static void run_checks(void); 220static void run_checks(void);
192static void set_source_ip(char *); 221static void set_source_ip(char *);
193static int add_target(char *); 222static int add_target(char *);
@@ -199,13 +228,28 @@ static void finish(int);
199static void crash(const char *, ...); 228static void crash(const char *, ...);
200 229
201/** external **/ 230/** external **/
202extern int optind, opterr, optopt; 231extern int optind;
203extern char *optarg; 232extern char *optarg;
204extern char **environ; 233extern char **environ;
205 234
206/** global variables **/ 235/** global variables **/
207static struct rta_host **table, *cursor, *list; 236static struct rta_host **table, *cursor, *list;
208static threshold crit = {80, 500000}, warn = {40, 200000}; 237
238static threshold crit = {
239 .pl = 80,
240 .rta = 500000,
241 .jitter = 0.0,
242 .mos = 0.0,
243 .score = 0.0
244};
245static threshold warn = {
246 .pl = 40,
247 .rta = 200000,
248 .jitter = 0.0,
249 .mos = 0.0,
250 .score = 0.0
251};
252
209static int mode, protocols, sockets, debug = 0, timeout = 10; 253static int mode, protocols, sockets, debug = 0, timeout = 10;
210static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; 254static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE;
211static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; 255static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN;
@@ -224,6 +268,12 @@ static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values
224static int min_hosts_alive = -1; 268static int min_hosts_alive = -1;
225float pkt_backoff_factor = 1.5; 269float pkt_backoff_factor = 1.5;
226float target_backoff_factor = 1.5; 270float target_backoff_factor = 1.5;
271bool rta_mode=false;
272bool pl_mode=false;
273bool jitter_mode=false;
274bool score_mode=false;
275bool mos_mode=false;
276bool order_mode=false;
227 277
228/** code start **/ 278/** code start **/
229static void 279static void
@@ -393,12 +443,14 @@ main(int argc, char **argv)
393 int icmp_sockerrno, udp_sockerrno, tcp_sockerrno; 443 int icmp_sockerrno, udp_sockerrno, tcp_sockerrno;
394 int result; 444 int result;
395 struct rta_host *host; 445 struct rta_host *host;
446#ifdef HAVE_SIGACTION
447 struct sigaction sig_action;
448#endif
396#ifdef SO_TIMESTAMP 449#ifdef SO_TIMESTAMP
397 int on = 1; 450 int on = 1;
398#endif 451#endif
399 char *source_ip = NULL; 452 char *source_ip = NULL;
400 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:64"; 453 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
401
402 setlocale (LC_ALL, ""); 454 setlocale (LC_ALL, "");
403 bindtextdomain (PACKAGE, LOCALEDIR); 455 bindtextdomain (PACKAGE, LOCALEDIR);
404 textdomain (PACKAGE); 456 textdomain (PACKAGE);
@@ -407,7 +459,7 @@ main(int argc, char **argv)
407 * that before pointer magic (esp. on network data) */ 459 * that before pointer magic (esp. on network data) */
408 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0; 460 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
409 461
410 address_family = -1; 462 address_family = -1;
411 int icmp_proto = IPPROTO_ICMP; 463 int icmp_proto = IPPROTO_ICMP;
412 464
413 /* get calling name the old-fashioned way for portability instead 465 /* get calling name the old-fashioned way for portability instead
@@ -422,10 +474,19 @@ main(int argc, char **argv)
422 table = NULL; 474 table = NULL;
423 475
424 mode = MODE_RTA; 476 mode = MODE_RTA;
477 /* Default critical thresholds */
425 crit.rta = 500000; 478 crit.rta = 500000;
426 crit.pl = 80; 479 crit.pl = 80;
480 crit.jitter = 50;
481 crit.mos= 3;
482 crit.score=70;
483 /* Default warning thresholds */
427 warn.rta = 200000; 484 warn.rta = 200000;
428 warn.pl = 40; 485 warn.pl = 40;
486 warn.jitter = 40;
487 warn.mos= 3.5;
488 warn.score=80;
489
429 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP; 490 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
430 pkt_interval = 80000; /* 80 msec packet interval by default */ 491 pkt_interval = 80000; /* 80 msec packet interval by default */
431 packets = 5; 492 packets = 5;
@@ -481,7 +542,8 @@ main(int argc, char **argv)
481 /* Reset argument scanning */ 542 /* Reset argument scanning */
482 optind = 1; 543 optind = 1;
483 544
484 unsigned short size; 545 unsigned long size;
546 bool err;
485 /* parse the arguments */ 547 /* parse the arguments */
486 for(i = 1; i < argc; i++) { 548 for(i = 1; i < argc; i++) {
487 while((arg = getopt(argc, argv, opts_str)) != EOF) { 549 while((arg = getopt(argc, argv, opts_str)) != EOF) {
@@ -490,7 +552,7 @@ main(int argc, char **argv)
490 debug++; 552 debug++;
491 break; 553 break;
492 case 'b': 554 case 'b':
493 size = (unsigned short)strtol(optarg,NULL,0); 555 size = strtol(optarg,NULL,0);
494 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && 556 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
495 size < MAX_PING_DATA) { 557 size < MAX_PING_DATA) {
496 icmp_data_size = size; 558 icmp_data_size = size;
@@ -545,6 +607,49 @@ main(int argc, char **argv)
545 print_help (); 607 print_help ();
546 exit (STATE_UNKNOWN); 608 exit (STATE_UNKNOWN);
547 break; 609 break;
610 case 'R': /* RTA mode */
611 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_rta_mode);
612 if (!err) {
613 crash("Failed to parse RTA threshold");
614 }
615
616 rta_mode=true;
617 break;
618 case 'P': /* packet loss mode */
619 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_packet_loss_mode);
620 if (!err) {
621 crash("Failed to parse packet loss threshold");
622 }
623
624 pl_mode=true;
625 break;
626 case 'J': /* jitter mode */
627 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_jitter_mode);
628 if (!err) {
629 crash("Failed to parse jitter threshold");
630 }
631
632 jitter_mode=true;
633 break;
634 case 'M': /* MOS mode */
635 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_mos_mode);
636 if (!err) {
637 crash("Failed to parse MOS threshold");
638 }
639
640 mos_mode=true;
641 break;
642 case 'S': /* score mode */
643 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_score_mode);
644 if (!err) {
645 crash("Failed to parse score threshold");
646 }
647
648 score_mode=true;
649 break;
650 case 'O': /* out of order mode */
651 order_mode=true;
652 break;
548 } 653 }
549 } 654 }
550 } 655 }
@@ -565,10 +670,10 @@ main(int argc, char **argv)
565 add_target(*argv); 670 add_target(*argv);
566 argv++; 671 argv++;
567 } 672 }
673
568 if(!targets) { 674 if(!targets) {
569 errno = 0; 675 errno = 0;
570 crash("No hosts to check"); 676 crash("No hosts to check");
571 exit(3);
572 } 677 }
573 678
574 // add_target might change address_family 679 // add_target might change address_family
@@ -631,11 +736,25 @@ main(int argc, char **argv)
631 if(warn.pl > crit.pl) warn.pl = crit.pl; 736 if(warn.pl > crit.pl) warn.pl = crit.pl;
632 if(warn.rta > crit.rta) warn.rta = crit.rta; 737 if(warn.rta > crit.rta) warn.rta = crit.rta;
633 if(warn_down > crit_down) crit_down = warn_down; 738 if(warn_down > crit_down) crit_down = warn_down;
634 739 if(warn.jitter > crit.jitter) crit.jitter = warn.jitter;
740 if(warn.mos < crit.mos) warn.mos = crit.mos;
741 if(warn.score < crit.score) warn.score = crit.score;
742
743#ifdef HAVE_SIGACTION
744 sig_action.sa_sigaction = NULL;
745 sig_action.sa_handler = finish;
746 sigfillset(&sig_action.sa_mask);
747 sig_action.sa_flags = SA_NODEFER|SA_RESTART;
748 sigaction(SIGINT, &sig_action, NULL);
749 sigaction(SIGHUP, &sig_action, NULL);
750 sigaction(SIGTERM, &sig_action, NULL);
751 sigaction(SIGALRM, &sig_action, NULL);
752#else /* HAVE_SIGACTION */
635 signal(SIGINT, finish); 753 signal(SIGINT, finish);
636 signal(SIGHUP, finish); 754 signal(SIGHUP, finish);
637 signal(SIGTERM, finish); 755 signal(SIGTERM, finish);
638 signal(SIGALRM, finish); 756 signal(SIGALRM, finish);
757#endif /* HAVE_SIGACTION */
639 if(debug) printf("Setting alarm timeout to %u seconds\n", timeout); 758 if(debug) printf("Setting alarm timeout to %u seconds\n", timeout);
640 alarm(timeout); 759 alarm(timeout);
641 760
@@ -685,7 +804,11 @@ main(int argc, char **argv)
685 } 804 }
686 805
687 host = list; 806 host = list;
688 table = (struct rta_host**)malloc(sizeof(struct rta_host **) * targets); 807 table = malloc(sizeof(struct rta_host *) * targets);
808 if(!table) {
809 crash("main(): malloc failed for host table");
810 }
811
689 i = 0; 812 i = 0;
690 while(host) { 813 while(host) {
691 host->id = i*packets; 814 host->id = i*packets;
@@ -772,6 +895,7 @@ wait_for_reply(int sock, u_int t)
772 struct icmp_ping_data data; 895 struct icmp_ping_data data;
773 struct timeval wait_start, now; 896 struct timeval wait_start, now;
774 u_int tdiff, i, per_pkt_wait; 897 u_int tdiff, i, per_pkt_wait;
898 double jitter_tmp;
775 899
776 if (!(packet.buf = malloc(icmp_pkt_size))) { 900 if (!(packet.buf = malloc(icmp_pkt_size))) {
777 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", 901 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
@@ -890,12 +1014,44 @@ wait_for_reply(int sock, u_int t)
890 1014
891 tdiff = get_timevaldiff(&data.stime, &now); 1015 tdiff = get_timevaldiff(&data.stime, &now);
892 1016
1017 if (host->last_tdiff>0) {
1018 /* Calculate jitter */
1019 if (host->last_tdiff > tdiff) {
1020 jitter_tmp = host->last_tdiff - tdiff;
1021 } else {
1022 jitter_tmp = tdiff - host->last_tdiff;
1023 }
1024
1025 if (host->jitter==0) {
1026 host->jitter=jitter_tmp;
1027 host->jitter_max=jitter_tmp;
1028 host->jitter_min=jitter_tmp;
1029 } else {
1030 host->jitter+=jitter_tmp;
1031
1032 if (jitter_tmp < host->jitter_min) {
1033 host->jitter_min=jitter_tmp;
1034 }
1035
1036 if (jitter_tmp > host->jitter_max) {
1037 host->jitter_max=jitter_tmp;
1038 }
1039 }
1040
1041 /* Check if packets in order */
1042 if (host->last_icmp_seq >= packet.icp->icmp_seq)
1043 host->order_status=STATE_CRITICAL;
1044 }
1045 host->last_tdiff=tdiff;
1046
1047 host->last_icmp_seq=packet.icp->icmp_seq;
1048
893 host->time_waited += tdiff; 1049 host->time_waited += tdiff;
894 host->icmp_recv++; 1050 host->icmp_recv++;
895 icmp_recv++; 1051 icmp_recv++;
896 if (tdiff > host->rtmax) 1052 if (tdiff > (unsigned int)host->rtmax)
897 host->rtmax = tdiff; 1053 host->rtmax = tdiff;
898 if (tdiff < host->rtmin) 1054 if (tdiff < (unsigned int)host->rtmin)
899 host->rtmin = tdiff; 1055 host->rtmin = tdiff;
900 1056
901 if(debug) { 1057 if(debug) {
@@ -1056,7 +1212,9 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
1056 int n, ret; 1212 int n, ret;
1057 struct timeval to, then, now; 1213 struct timeval to, then, now;
1058 fd_set rd, wr; 1214 fd_set rd, wr;
1215#ifdef HAVE_MSGHDR_MSG_CONTROL
1059 char ans_data[4096]; 1216 char ans_data[4096];
1217#endif // HAVE_MSGHDR_MSG_CONTROL
1060 struct msghdr hdr; 1218 struct msghdr hdr;
1061 struct iovec iov; 1219 struct iovec iov;
1062#ifdef SO_TIMESTAMP 1220#ifdef SO_TIMESTAMP
@@ -1094,8 +1252,10 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
1094 hdr.msg_namelen = slen; 1252 hdr.msg_namelen = slen;
1095 hdr.msg_iov = &iov; 1253 hdr.msg_iov = &iov;
1096 hdr.msg_iovlen = 1; 1254 hdr.msg_iovlen = 1;
1255#ifdef HAVE_MSGHDR_MSG_CONTROL
1097 hdr.msg_control = ans_data; 1256 hdr.msg_control = ans_data;
1098 hdr.msg_controllen = sizeof(ans_data); 1257 hdr.msg_controllen = sizeof(ans_data);
1258#endif
1099 1259
1100 ret = recvmsg(sock, &hdr, 0); 1260 ret = recvmsg(sock, &hdr, 0);
1101#ifdef SO_TIMESTAMP 1261#ifdef SO_TIMESTAMP
@@ -1125,6 +1285,8 @@ finish(int sig)
1125 {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; 1285 {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"};
1126 int hosts_ok = 0; 1286 int hosts_ok = 0;
1127 int hosts_warn = 0; 1287 int hosts_warn = 0;
1288 int this_status;
1289 double R;
1128 1290
1129 alarm(0); 1291 alarm(0);
1130 if(debug > 1) printf("finish(%d) called\n", sig); 1292 if(debug > 1) printf("finish(%d) called\n", sig);
@@ -1140,9 +1302,12 @@ finish(int sig)
1140 } 1302 }
1141 1303
1142 /* iterate thrice to calculate values, give output, and print perfparse */ 1304 /* iterate thrice to calculate values, give output, and print perfparse */
1305 status=STATE_OK;
1143 host = list; 1306 host = list;
1144 1307
1145 while(host) { 1308 while(host) {
1309 this_status = STATE_OK;
1310
1146 if(!host->icmp_recv) { 1311 if(!host->icmp_recv) {
1147 /* rta 0 is ofcourse not entirely correct, but will still show up 1312 /* rta 0 is ofcourse not entirely correct, but will still show up
1148 * conspicuously as missing entries in perfparse and cacti */ 1313 * conspicuously as missing entries in perfparse and cacti */
@@ -1151,26 +1316,138 @@ finish(int sig)
1151 status = STATE_CRITICAL; 1316 status = STATE_CRITICAL;
1152 /* up the down counter if not already counted */ 1317 /* up the down counter if not already counted */
1153 if(!(host->flags & FLAG_LOST_CAUSE) && targets_alive) targets_down++; 1318 if(!(host->flags & FLAG_LOST_CAUSE) && targets_alive) targets_down++;
1154 } 1319 } else {
1155 else {
1156 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent; 1320 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent;
1157 rta = (double)host->time_waited / host->icmp_recv; 1321 rta = (double)host->time_waited / host->icmp_recv;
1158 } 1322 }
1323
1324 if (host->icmp_recv>1) {
1325 /*
1326 * This algorithm is probably pretty much blindly copied from
1327 * locations like this one: https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos
1328 * It calculates a MOS value (range of 1 to 5, where 1 is bad and 5 really good).
1329 * According to some quick research MOS originates from the Audio/Video transport network area.
1330 * Whether it can and should be computed from ICMP data, I can not say.
1331 *
1332 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value
1333 *
1334 * MOS stands likely for Mean Opinion Score ( https://en.wikipedia.org/wiki/Mean_Opinion_Score )
1335 *
1336 * More links:
1337 * - https://confluence.slac.stanford.edu/display/IEPM/MOS
1338 */
1339 host->jitter=(host->jitter / (host->icmp_recv - 1)/1000);
1340
1341 /*
1342 * Take the average round trip latency (in milliseconds), add
1343 * round trip jitter, but double the impact to latency
1344 * then add 10 for protocol latencies (in milliseconds).
1345 */
1346 host->EffectiveLatency = (rta/1000) + host->jitter * 2 + 10;
1347
1348 if (host->EffectiveLatency < 160) {
1349 R = 93.2 - (host->EffectiveLatency / 40);
1350 } else {
1351 R = 93.2 - ((host->EffectiveLatency - 120) / 10);
1352 }
1353
1354 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a
1355 // loss of 5% will be entered as 5).
1356 R = R - (pl * 2.5);
1357
1358 if (R < 0) {
1359 R = 0;
1360 }
1361
1362 host->score = R;
1363 host->mos= 1 + ((0.035) * R) + ((.000007) * R * (R-60) * (100-R));
1364 } else {
1365 host->jitter=0;
1366 host->jitter_min=0;
1367 host->jitter_max=0;
1368 host->mos=0;
1369 }
1370
1159 host->pl = pl; 1371 host->pl = pl;
1160 host->rta = rta; 1372 host->rta = rta;
1161 if(pl >= crit.pl || rta >= crit.rta) { 1373
1162 status = STATE_CRITICAL; 1374 /* if no new mode selected, use old schema */
1375 if (!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && !order_mode) {
1376 rta_mode = true;
1377 pl_mode = true;
1163 } 1378 }
1164 else if(!status && (pl >= warn.pl || rta >= warn.rta)) { 1379
1165 status = STATE_WARNING; 1380 /* Check which mode is on and do the warn / Crit stuff */
1166 hosts_warn++; 1381 if (rta_mode) {
1382 if(rta >= crit.rta) {
1383 this_status = STATE_CRITICAL;
1384 status = STATE_CRITICAL;
1385 host->rta_status=STATE_CRITICAL;
1386 } else if(status!=STATE_CRITICAL && (rta >= warn.rta)) {
1387 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1388 status = STATE_WARNING;
1389 host->rta_status=STATE_WARNING;
1390 }
1391 }
1392
1393 if (pl_mode) {
1394 if(pl >= crit.pl) {
1395 this_status = STATE_CRITICAL;
1396 status = STATE_CRITICAL;
1397 host->pl_status=STATE_CRITICAL;
1398 } else if(status!=STATE_CRITICAL && (pl >= warn.pl)) {
1399 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1400 status = STATE_WARNING;
1401 host->pl_status=STATE_WARNING;
1402 }
1403 }
1404
1405 if (jitter_mode) {
1406 if(host->jitter >= crit.jitter) {
1407 this_status = STATE_CRITICAL;
1408 status = STATE_CRITICAL;
1409 host->jitter_status=STATE_CRITICAL;
1410 } else if(status!=STATE_CRITICAL && (host->jitter >= warn.jitter)) {
1411 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1412 status = STATE_WARNING;
1413 host->jitter_status=STATE_WARNING;
1414 }
1415 }
1416
1417 if (mos_mode) {
1418 if(host->mos <= crit.mos) {
1419 this_status = STATE_CRITICAL;
1420 status = STATE_CRITICAL;
1421 host->mos_status=STATE_CRITICAL;
1422 } else if(status!=STATE_CRITICAL && (host->mos <= warn.mos)) {
1423 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1424 status = STATE_WARNING;
1425 host->mos_status=STATE_WARNING;
1426 }
1427 }
1428
1429 if (score_mode) {
1430 if(host->score <= crit.score) {
1431 this_status = STATE_CRITICAL;
1432 status = STATE_CRITICAL;
1433 host->score_status=STATE_CRITICAL;
1434 } else if(status!=STATE_CRITICAL && (host->score <= warn.score)) {
1435 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1436 status = STATE_WARNING;
1437 host->score_status=STATE_WARNING;
1438 }
1167 } 1439 }
1168 else { 1440
1441 if (this_status == STATE_WARNING) {
1442 hosts_warn++;
1443 } else if (this_status == STATE_OK) {
1169 hosts_ok++; 1444 hosts_ok++;
1170 } 1445 }
1171 1446
1172 host = host->next; 1447 host = host->next;
1173 } 1448 }
1449
1450
1174 /* this is inevitable */ 1451 /* this is inevitable */
1175 if(!targets_alive) status = STATE_CRITICAL; 1452 if(!targets_alive) status = STATE_CRITICAL;
1176 if(min_hosts_alive > -1) { 1453 if(min_hosts_alive > -1) {
@@ -1181,6 +1458,7 @@ finish(int sig)
1181 1458
1182 host = list; 1459 host = list;
1183 while(host) { 1460 while(host) {
1461
1184 if(debug) puts(""); 1462 if(debug) puts("");
1185 if(i) { 1463 if(i) {
1186 if(i < targets) printf(" :: "); 1464 if(i < targets) printf(" :: ");
@@ -1189,6 +1467,8 @@ finish(int sig)
1189 i++; 1467 i++;
1190 if(!host->icmp_recv) { 1468 if(!host->icmp_recv) {
1191 status = STATE_CRITICAL; 1469 status = STATE_CRITICAL;
1470 host->rtmin=0;
1471 host->jitter_min=0;
1192 if(host->flags & FLAG_LOST_CAUSE) { 1472 if(host->flags & FLAG_LOST_CAUSE) {
1193 char address[INET6_ADDRSTRLEN]; 1473 char address[INET6_ADDRSTRLEN];
1194 parse_address(&host->error_addr, address, sizeof(address)); 1474 parse_address(&host->error_addr, address, sizeof(address));
@@ -1197,31 +1477,117 @@ finish(int sig)
1197 get_icmp_error_msg(host->icmp_type, host->icmp_code), 1477 get_icmp_error_msg(host->icmp_type, host->icmp_code),
1198 address, 1478 address,
1199 100); 1479 100);
1200 } 1480 } else { /* not marked as lost cause, so we have no flags for it */
1201 else { /* not marked as lost cause, so we have no flags for it */
1202 printf("%s: rta nan, lost 100%%", host->name); 1481 printf("%s: rta nan, lost 100%%", host->name);
1203 } 1482 }
1483 } else { /* !icmp_recv */
1484 printf("%s", host->name);
1485 /* rta text output */
1486 if (rta_mode) {
1487 if (status == STATE_OK)
1488 printf(" rta %0.3fms", host->rta / 1000);
1489 else if (status==STATE_WARNING && host->rta_status==status)
1490 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)warn.rta/1000);
1491 else if (status==STATE_CRITICAL && host->rta_status==status)
1492 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)crit.rta/1000);
1493 }
1494 /* pl text output */
1495 if (pl_mode) {
1496 if (status == STATE_OK)
1497 printf(" lost %u%%", host->pl);
1498 else if (status==STATE_WARNING && host->pl_status==status)
1499 printf(" lost %u%% > %u%%", host->pl, warn.pl);
1500 else if (status==STATE_CRITICAL && host->pl_status==status)
1501 printf(" lost %u%% > %u%%", host->pl, crit.pl);
1502 }
1503 /* jitter text output */
1504 if (jitter_mode) {
1505 if (status == STATE_OK)
1506 printf(" jitter %0.3fms", (float)host->jitter);
1507 else if (status==STATE_WARNING && host->jitter_status==status)
1508 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, warn.jitter);
1509 else if (status==STATE_CRITICAL && host->jitter_status==status)
1510 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, crit.jitter);
1511 }
1512 /* mos text output */
1513 if (mos_mode) {
1514 if (status == STATE_OK)
1515 printf(" MOS %0.1f", (float)host->mos);
1516 else if (status==STATE_WARNING && host->mos_status==status)
1517 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)warn.mos);
1518 else if (status==STATE_CRITICAL && host->mos_status==status)
1519 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)crit.mos);
1520 }
1521 /* score text output */
1522 if (score_mode) {
1523 if (status == STATE_OK)
1524 printf(" Score %u", (int)host->score);
1525 else if (status==STATE_WARNING && host->score_status==status )
1526 printf(" Score %u < %u", (int)host->score, (int)warn.score);
1527 else if (status==STATE_CRITICAL && host->score_status==status )
1528 printf(" Score %u < %u", (int)host->score, (int)crit.score);
1529 }
1530 /* order statis text output */
1531 if (order_mode) {
1532 if (status == STATE_OK)
1533 printf(" Packets in order");
1534 else if (status==STATE_CRITICAL && host->order_status==status)
1535 printf(" Packets out of order");
1536 }
1204 } 1537 }
1205 else { /* !icmp_recv */
1206 printf("%s: rta %0.3fms, lost %u%%",
1207 host->name, host->rta / 1000, host->pl);
1208 }
1209
1210 host = host->next; 1538 host = host->next;
1211 } 1539 }
1212 1540
1213 /* iterate once more for pretty perfparse output */ 1541 /* iterate once more for pretty perfparse output */
1214 printf("|"); 1542 if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) {
1543 printf("|");
1544 }
1215 i = 0; 1545 i = 0;
1216 host = list; 1546 host = list;
1217 while(host) { 1547 while(host) {
1218 if(debug) puts(""); 1548 if(debug) puts("");
1219 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %spl=%u%%;%u;%u;; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ", 1549
1550 if (rta_mode && host->pl<100) {
1551 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",
1220 (targets > 1) ? host->name : "", 1552 (targets > 1) ? host->name : "",
1221 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, 1553 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000,
1222 (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl,
1223 (targets > 1) ? host->name : "", (float)host->rtmax / 1000, 1554 (targets > 1) ? host->name : "", (float)host->rtmax / 1000,
1224 (targets > 1) ? host->name : "", (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0); 1555 (targets > 1) ? host->name : "", (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0);
1556 }
1557
1558 if (pl_mode) {
1559 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl);
1560 }
1561
1562 if (jitter_mode && host->pl<100) {
1563 printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; %sjitter_min=%0.3fms;;;; ",
1564 (targets > 1) ? host->name : "",
1565 (float)host->jitter,
1566 (float)warn.jitter,
1567 (float)crit.jitter,
1568 (targets > 1) ? host->name : "",
1569 (float)host->jitter_max / 1000, (targets > 1) ? host->name : "",
1570 (float)host->jitter_min / 1000
1571 );
1572 }
1573
1574 if (mos_mode && host->pl<100) {
1575 printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ",
1576 (targets > 1) ? host->name : "",
1577 (float)host->mos,
1578 (float)warn.mos,
1579 (float)crit.mos
1580 );
1581 }
1582
1583 if (score_mode && host->pl<100) {
1584 printf("%sscore=%u;%u;%u;0;100 ",
1585 (targets > 1) ? host->name : "",
1586 (int)host->score,
1587 (int)warn.score,
1588 (int)crit.score
1589 );
1590 }
1225 1591
1226 host = host->next; 1592 host = host->next;
1227 } 1593 }
@@ -1312,6 +1678,7 @@ add_target_ip(char *arg, struct sockaddr_storage *in)
1312 /* set the values. use calling name for output */ 1678 /* set the values. use calling name for output */
1313 host->name = strdup(arg); 1679 host->name = strdup(arg);
1314 1680
1681
1315 /* fill out the sockaddr_storage struct */ 1682 /* fill out the sockaddr_storage struct */
1316 if(address_family == AF_INET) { 1683 if(address_family == AF_INET) {
1317 host_sin = (struct sockaddr_in *)&host->saddr_in; 1684 host_sin = (struct sockaddr_in *)&host->saddr_in;
@@ -1324,7 +1691,22 @@ add_target_ip(char *arg, struct sockaddr_storage *in)
1324 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr); 1691 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr);
1325 } 1692 }
1326 1693
1694 /* fill out the sockaddr_in struct */
1327 host->rtmin = INFINITY; 1695 host->rtmin = INFINITY;
1696 host->rtmax = 0;
1697 host->jitter=0;
1698 host->jitter_max=0;
1699 host->jitter_min=INFINITY;
1700 host->last_tdiff=0;
1701 host->order_status=STATE_OK;
1702 host->last_icmp_seq=0;
1703 host->rta_status=0;
1704 host->pl_status=0;
1705 host->jitter_status=0;
1706 host->mos_status=0;
1707 host->score_status=0;
1708 host->pl_status=0;
1709
1328 1710
1329 if(!list) list = cursor = host; 1711 if(!list) list = cursor = host;
1330 else cursor->next = host; 1712 else cursor->next = host;
@@ -1408,7 +1790,7 @@ add_target(char *arg)
1408 } 1790 }
1409 break; 1791 break;
1410 } 1792 }
1411 freeaddrinfo(res); 1793 freeaddrinfo(res);
1412 1794
1413 return 0; 1795 return 0;
1414} 1796}
@@ -1472,7 +1854,7 @@ get_timevar(const char *str)
1472 1854
1473 /* unit might be given as ms|m (millisec), 1855 /* unit might be given as ms|m (millisec),
1474 * us|u (microsec) or just plain s, for seconds */ 1856 * us|u (microsec) or just plain s, for seconds */
1475 u = p = '\0'; 1857 p = '\0';
1476 u = str[len - 1]; 1858 u = str[len - 1];
1477 if(len >= 2 && !isdigit((int)str[len - 2])) p = str[len - 2]; 1859 if(len >= 2 && !isdigit((int)str[len - 2])) p = str[len - 2];
1478 if(p && u == 's') u = p; 1860 if(p && u == 's') u = p;
@@ -1530,6 +1912,81 @@ get_threshold(char *str, threshold *th)
1530 return 0; 1912 return 0;
1531} 1913}
1532 1914
1915/*
1916 * This functions receives a pointer to a string which should contain a threshold for the
1917 * rta, packet_loss, jitter, mos or score mode in the form number,number[m|%]* assigns the
1918 * parsed number to the corresponding threshold variable.
1919 * @param[in,out] str String containing the given threshold values
1920 * @param[in] length strlen(str)
1921 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned
1922 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned
1923 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score (exclusively)
1924 */
1925static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit, threshold_mode mode) {
1926 if (!str || !length || !warn || !crit) return false;
1927
1928
1929 // p points to the last char in str
1930 char *p = &str[length - 1];
1931
1932 // first_iteration is bof-stop on stupid libc's
1933 bool first_iteration = true;
1934
1935 while(p != &str[0]) {
1936 if( (*p == 'm') || (*p == '%') ) {
1937 *p = '\0';
1938 } else if(*p == ',' && !first_iteration) {
1939 *p = '\0'; /* reset it so get_timevar(str) works nicely later */
1940
1941 char *start_of_value = p + 1;
1942
1943 if (!parse_threshold2_helper(start_of_value, strlen(start_of_value), crit, mode)){
1944 return false;
1945 }
1946
1947 }
1948 first_iteration = false;
1949 p--;
1950 }
1951
1952 return parse_threshold2_helper(p, strlen(p), warn, mode);
1953}
1954
1955static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode) {
1956 char *resultChecker = {0};
1957
1958 switch (mode) {
1959 case const_rta_mode:
1960 thr->rta = strtod(s, &resultChecker) * 1000;
1961 break;
1962 case const_packet_loss_mode:
1963 thr->pl = (unsigned char)strtoul(s, &resultChecker, 0);
1964 break;
1965 case const_jitter_mode:
1966 thr->jitter = strtod(s, &resultChecker);
1967
1968 break;
1969 case const_mos_mode:
1970 thr->mos = strtod(s, &resultChecker);
1971 break;
1972 case const_score_mode:
1973 thr->score = strtod(s, &resultChecker);
1974 break;
1975 }
1976
1977 if (resultChecker == s) {
1978 // Failed to parse
1979 return false;
1980 }
1981
1982 if (resultChecker != (s + length)) {
1983 // Trailing symbols
1984 return false;
1985 }
1986
1987 return true;
1988}
1989
1533unsigned short 1990unsigned short
1534icmp_checksum(uint16_t *p, size_t n) 1991icmp_checksum(uint16_t *p, size_t n)
1535{ 1992{
@@ -1555,74 +2012,91 @@ icmp_checksum(uint16_t *p, size_t n)
1555void 2012void
1556print_help(void) 2013print_help(void)
1557{ 2014{
1558 2015 /*print_revision (progname);*/ /* FIXME: Why? */
1559 /*print_revision (progname);*/ /* FIXME: Why? */ 2016 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n");
1560 2017
1561 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n"); 2018 printf (COPYRIGHT, copyright, email);
1562 printf (COPYRIGHT, copyright, email); 2019
1563 2020 printf ("\n\n");
1564 printf ("\n\n"); 2021
1565 2022 print_usage ();
1566 print_usage (); 2023
1567 2024 printf (UT_HELP_VRSN);
1568 printf (UT_HELP_VRSN); 2025 printf (UT_EXTRA_OPTS);
1569 printf (UT_EXTRA_OPTS); 2026
1570 2027 printf (" %s\n", "-H");
1571 printf (" %s\n", "-H"); 2028 printf (" %s\n", _("specify a target"));
1572 printf (" %s\n", _("specify a target")); 2029 printf (" %s\n", "[-4|-6]");
1573 printf (" %s\n", "[-4|-6]"); 2030 printf (" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets"));
1574 printf (" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets")); 2031 printf (" %s\n", "-w");
1575 printf (" %s\n", "-w"); 2032 printf (" %s", _("warning threshold (currently "));
1576 printf (" %s", _("warning threshold (currently ")); 2033 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl);
1577 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); 2034 printf (" %s\n", "-c");
1578 printf (" %s\n", "-c"); 2035 printf (" %s", _("critical threshold (currently "));
1579 printf (" %s", _("critical threshold (currently ")); 2036 printf ("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl);
1580 printf ("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl); 2037
1581 printf (" %s\n", "-s"); 2038 printf (" %s\n", "-R");
1582 printf (" %s\n", _("specify a source IP address or device name")); 2039 printf (" %s\n", _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms"));
1583 printf (" %s\n", "-n"); 2040 printf (" %s\n", "-P");
1584 printf (" %s", _("number of packets to send (currently ")); 2041 printf (" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
1585 printf ("%u)\n",packets); 2042 printf (" %s\n", "-J");
1586 printf (" %s\n", "-i"); 2043 printf (" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms "));
1587 printf (" %s", _("max packet interval (currently ")); 2044 printf (" %s\n", "-M");
1588 printf ("%0.3fms)\n",(float)pkt_interval / 1000); 2045 printf (" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0"));
1589 printf (" %s\n", "-I"); 2046 printf (" %s\n", "-S");
1590 printf (" %s", _("max target interval (currently ")); 2047 printf (" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 "));
1591 printf ("%0.3fms)\n", (float)target_interval / 1000); 2048 printf (" %s\n", "-O");
1592 printf (" %s\n", "-m"); 2049 printf (" %s\n", _("detect out of order ICMP packts "));
1593 printf (" %s",_("number of alive hosts required for success")); 2050 printf (" %s\n", "-H");
1594 printf ("\n"); 2051 printf (" %s\n", _("specify a target"));
1595 printf (" %s\n", "-l"); 2052 printf (" %s\n", "-s");
1596 printf (" %s", _("TTL on outgoing packets (currently ")); 2053 printf (" %s\n", _("specify a source IP address or device name"));
1597 printf ("%u)\n", ttl); 2054 printf (" %s\n", "-n");
1598 printf (" %s\n", "-t"); 2055 printf (" %s", _("number of packets to send (currently "));
1599 printf (" %s",_("timeout value (seconds, currently ")); 2056 printf ("%u)\n",packets);
1600 printf ("%u)\n", timeout); 2057 printf (" %s\n", "-p");
1601 printf (" %s\n", "-b"); 2058 printf (" %s", _("number of packets to send (currently "));
1602 printf (" %s\n", _("Number of icmp data bytes to send")); 2059 printf ("%u)\n",packets);
1603 printf (" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"),icmp_data_size, ICMP_MINLEN); 2060 printf (" %s\n", "-i");
1604 printf (" %s\n", "-v"); 2061 printf (" %s", _("max packet interval (currently "));
1605 printf (" %s\n", _("verbose")); 2062 printf ("%0.3fms)\n",(float)pkt_interval / 1000);
1606 2063 printf (" %s\n", "-I");
1607 printf ("\n"); 2064 printf (" %s", _("max target interval (currently "));
1608 printf ("%s\n", _("Notes:")); 2065 printf ("%0.3fms)\n", (float)target_interval / 1000);
1609 printf (" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not.")); 2066 printf (" %s\n", "-m");
1610 printf ("\n"); 2067 printf (" %s",_("number of alive hosts required for success"));
1611 printf (" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); 2068 printf ("\n");
1612 printf (" %s\n", _("packet loss. The default values should work well for most users.")); 2069 printf (" %s\n", "-l");
1613 printf (" %s\n", _("You can specify different RTA factors using the standardized abbreviations")); 2070 printf (" %s", _("TTL on outgoing packets (currently "));
1614 printf (" %s\n", _("us (microseconds), ms (milliseconds, default) or just plain s for seconds.")); 2071 printf ("%u)\n", ttl);
1615/* -d not yet implemented */ 2072 printf (" %s\n", "-t");
1616/* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops")); 2073 printf (" %s",_("timeout value (seconds, currently "));
1617 printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent.")); 2074 printf ("%u)\n", timeout);
1618 printf ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not."));*/ 2075 printf (" %s\n", "-b");
1619 printf ("\n"); 2076 printf (" %s\n", _("Number of icmp data bytes to send"));
1620 printf (" %s\n", _("The -v switch can be specified several times for increased verbosity.")); 2077 printf (" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"),icmp_data_size, ICMP_MINLEN);
1621/* printf ("%s\n", _("Long options are currently unsupported.")); 2078 printf (" %s\n", "-v");
1622 printf ("%s\n", _("Options marked with * require an argument")); 2079 printf (" %s\n", _("verbose"));
1623*/ 2080 printf ("\n");
1624 2081 printf ("%s\n", _("Notes:"));
1625 printf (UT_SUPPORT); 2082 printf (" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P"));
2083 printf (" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not."));
2084 printf ("\n");
2085 printf (" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%"));
2086 printf (" %s\n", _("packet loss. The default values should work well for most users."));
2087 printf (" %s\n", _("You can specify different RTA factors using the standardized abbreviations"));
2088 printf (" %s\n", _("us (microseconds), ms (milliseconds, default) or just plain s for seconds."));
2089 /* -d not yet implemented */
2090 /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops"));
2091 printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent."));
2092 printf ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not."));*/
2093 printf ("\n");
2094 printf (" %s\n", _("The -v switch can be specified several times for increased verbosity."));
2095 /* printf ("%s\n", _("Long options are currently unsupported."));
2096 printf ("%s\n", _("Options marked with * require an argument"));
2097 */
2098
2099 printf (UT_SUPPORT);
1626} 2100}
1627 2101
1628 2102
@@ -1630,6 +2104,6 @@ print_help(void)
1630void 2104void
1631print_usage (void) 2105print_usage (void)
1632{ 2106{
1633 printf ("%s\n", _("Usage:")); 2107 printf ("%s\n", _("Usage:"));
1634 printf(" %s [options] [-H] host1 host2 hostN\n", progname); 2108 printf(" %s [options] [-H] host1 host2 hostN\n", progname);
1635} 2109}