check_icmp.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416
  1. /*
  2. * $Id$
  3. *
  4. * This is a hack of fping2 made to work with nagios.
  5. * It's fast and removes the necessity of parsing another programs output.
  6. *
  7. * VIEWING NOTES:
  8. * This file was formatted with tab indents at a tab stop of 4.
  9. *
  10. * It is highly recommended that your editor is set to this
  11. * tab stop setting for viewing and editing.
  12. *
  13. * COPYLEFT;
  14. * This programs copyright status is currently undetermined. Much of
  15. * the code in it comes from the fping2 program which used to be licensed
  16. * under the Stanford General Software License (available at
  17. * http://graphics.stanford.edu/software/license.html). It is presently
  18. * unclear what license (if any) applies to the original code at the
  19. * moment.
  20. *
  21. * The fping website can be found at http://www.fping.com
  22. */
  23. const char *progname = "check_icmp";
  24. const char *revision = "$Revision$";
  25. const char *copyright = "2004";
  26. const char *email = "nagiosplug-devel@lists.sourceforge.net";
  27. #include "common.h"
  28. #include "netutils.h"
  29. #include "utils.h"
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <time.h>
  33. #include <signal.h>
  34. #include <unistd.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <stddef.h>
  38. #include <sys/types.h>
  39. #include <sys/time.h>
  40. #include <sys/socket.h>
  41. #include <sys/file.h>
  42. #include <netinet/in_systm.h>
  43. #include <netinet/in.h>
  44. #include <netinet/ip.h>
  45. #include <netinet/ip_icmp.h>
  46. #include <arpa/inet.h>
  47. #include <netdb.h>
  48. /* RS6000 has sys/select.h */
  49. #ifdef HAVE_SYS_SELECT_H
  50. #include <sys/select.h>
  51. #endif /* HAVE_SYS_SELECT_H */
  52. /* rta threshold values can't be larger than MAXTTL seconds */
  53. #ifndef MAXTTL
  54. # define MAXTTL 255
  55. #endif
  56. #ifndef IPDEFTTL
  57. # define IPDEFTTL 64
  58. #endif
  59. /*** externals ***/
  60. extern char *optarg;
  61. extern int optind, opterr;
  62. /*** Constants ***/
  63. //#define EMAIL "ae@op5.se"
  64. //#define VERSION "0.8.1"
  65. #ifndef INADDR_NONE
  66. # define INADDR_NONE 0xffffffU
  67. #endif
  68. /*** Ping packet defines ***/
  69. /* data added after ICMP header for our nefarious purposes */
  70. typedef struct ping_data {
  71. unsigned int ping_count; /* counts up to -[n|p] count or 1 */
  72. struct timeval ping_ts; /* time sent */
  73. } PING_DATA;
  74. #define MIN_PING_DATA sizeof(PING_DATA)
  75. #define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */
  76. #define SIZE_IP_HDR 20
  77. #define SIZE_ICMP_HDR ICMP_MINLEN /* from ip_icmp.h */
  78. #define MAX_PING_DATA (MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR)
  79. /*
  80. * Interval is the minimum amount of time between sending a ping packet to
  81. * any host.
  82. *
  83. * Perhost_interval is the minimum amount of time between sending a ping
  84. * packet to a particular responding host
  85. *
  86. * Timeout is the initial amount of time between sending a ping packet to
  87. * a particular non-responding host.
  88. *
  89. * Retry is the number of ping packets to send to a non-responding host
  90. * before giving up (in is-it-alive mode).
  91. *
  92. * Backoff factor is how much longer to wait on successive retries.
  93. */
  94. #ifndef DEFAULT_INTERVAL
  95. #define DEFAULT_INTERVAL 25 /* default time between packets (msec) */
  96. #endif
  97. #ifndef DEFAULT_RETRY
  98. #define DEFAULT_RETRY 1 /* number of times to retry a host */
  99. #endif
  100. #ifndef DEFAULT_TIMEOUT
  101. # define DEFAULT_TIMEOUT 1000
  102. #endif
  103. #ifndef DEFAULT_BACKOFF_FACTOR
  104. #define DEFAULT_BACKOFF_FACTOR 1.5 /* exponential timeout factor */
  105. #endif
  106. #define MIN_BACKOFF_FACTOR 1.0 /* exponential timeout factor */
  107. #define MAX_BACKOFF_FACTOR 5.0 /* exponential timeout factor */
  108. #ifndef DNS_TIMEOUT
  109. #define DNS_TIMEOUT 1000 /* time in usec for dns retry */
  110. #endif
  111. #ifndef MAX_RTA_THRESHOLD_VALUE
  112. # define MAX_RTA_THRESHOLD_VALUE 120*1000000 /* 2 minutes should be enough */
  113. #endif
  114. #ifndef MIN_RTA_THRESHOLD_VALUE
  115. # define MIN_RTA_THRESHOLD_VALUE 10000 /* minimum RTA threshold value */
  116. #endif
  117. /* sized so as to be like traditional ping */
  118. #define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA + 44)
  119. /* maxima and minima */
  120. #define MAX_COUNT 50 /* max count even if we're root */
  121. #define MAX_RETRY 5
  122. #define MIN_INTERVAL 25 /* msecs */
  123. #define MIN_TIMEOUT 50 /* msecs */
  124. /* response time array flags */
  125. #define RESP_WAITING -1
  126. #define RESP_UNUSED -2
  127. #define ICMP_UNREACH_MAXTYPE 15
  128. /* entry used to keep track of each host we are pinging */
  129. struct host_entry {
  130. int i; /* index into array */
  131. char *name; /* name as given by user */
  132. char *host; /* text description of host */
  133. struct sockaddr_in saddr; /* internet address */
  134. unsigned short **pr; /* TCP port range to check for connectivity */
  135. struct timeval last_send_time; /* time of last packet sent */
  136. unsigned int num_sent; /* number of ping packets sent */
  137. unsigned int num_recv; /* number of pings received */
  138. unsigned int total_time; /* sum of response times */
  139. unsigned int status; /* this hosts status */
  140. unsigned int running; /* unset when through sending */
  141. unsigned int waiting; /* waiting for response */
  142. int *resp_times; /* individual response times */
  143. struct host_entry *prev, *next; /* doubly linked list */
  144. };
  145. typedef struct host_entry HOST_ENTRY;
  146. struct host_name_list {
  147. char *entry;
  148. struct host_name_list *next;
  149. };
  150. /* threshold structure */
  151. struct threshold {
  152. unsigned int pl; /* packet loss */
  153. unsigned int rta; /* roundtrip time average */
  154. };
  155. typedef struct threshold threshold;
  156. /*****************************************************************************
  157. * Global Variables *
  158. *****************************************************************************/
  159. HOST_ENTRY *rrlist = NULL; /* linked list of hosts be pinged */
  160. HOST_ENTRY **table = NULL; /* array of pointers to items in the list */
  161. HOST_ENTRY *cursor;
  162. char *prog; /* our name */
  163. int ident; /* our pid, for marking icmp packets */
  164. int sock; /* socket */
  165. u_int debug = 0;
  166. /* threshold value defaults;
  167. * WARNING; 60% packetloss or 200 msecs round trip average
  168. * CRITICAL; 80% packetloss or 500 msecs round trip average */
  169. threshold warn = {60, 200 * 1000};
  170. threshold crit = {80, 500 * 1000};
  171. /* times get *100 because all times are calculated in 10 usec units, not ms */
  172. unsigned int retry = DEFAULT_RETRY;
  173. u_int timeout = DEFAULT_TIMEOUT * 100;
  174. u_int interval = DEFAULT_INTERVAL * 100;
  175. float backoff = DEFAULT_BACKOFF_FACTOR;
  176. u_int select_time; /* calculated using maximum threshold rta value */
  177. u_int ping_data_size = DEFAULT_PING_DATA_SIZE;
  178. u_int ping_pkt_size;
  179. unsigned int count = 5;
  180. unsigned int trials = 1;
  181. /* global stats */
  182. int total_replies = 0;
  183. int num_jobs = 0; /* number of hosts still to do */
  184. int num_hosts = 0; /* total number of hosts */
  185. int num_alive = 0; /* total number alive */
  186. int num_unreachable = 0; /* total number unreachable */
  187. int num_noaddress = 0; /* total number of addresses not found */
  188. int num_timeout = 0; /* number of timed out packets */
  189. int num_pingsent = 0; /* total pings sent */
  190. int num_pingreceived = 0; /* total pings received */
  191. int num_othericmprcvd = 0; /* total non-echo-reply ICMP received */
  192. struct timeval current_time; /* current time (pseudo) */
  193. struct timeval my_start_time; /* conflict with utils.c 33, but not found ?? */
  194. struct timeval my_end_time; /* conflict with utils.c 33, but not found ?? */
  195. struct timeval last_send_time; /* time last ping was sent */
  196. struct timezone tz;
  197. /* switches */
  198. int generate_flag = 0; /* flag for IP list generation */
  199. int stats_flag, unreachable_flag, alive_flag;
  200. int elapsed_flag, version_flag, count_flag;
  201. int name_flag, addr_flag, backoff_flag;
  202. int multif_flag;
  203. /*** prototypes ***/
  204. void add_name(char *);
  205. void add_addr(char *, char *, struct in_addr);
  206. char *na_cat(char *, struct in_addr);
  207. char *cpystr(char *);
  208. void crash(char *);
  209. char *get_host_by_address(struct in_addr);
  210. int in_cksum(u_short *, int);
  211. void u_sleep(int);
  212. int recvfrom_wto(int, char *, int, struct sockaddr *, int);
  213. void remove_job(HOST_ENTRY *);
  214. void send_ping(int, HOST_ENTRY *);
  215. long timeval_diff(struct timeval *, struct timeval *);
  216. //void usage(void);
  217. int wait_for_reply(int);
  218. void finish(void);
  219. int handle_random_icmp(struct icmp *, struct sockaddr_in *);
  220. char *sprint_tm(int);
  221. int get_threshold(char *, threshold *);
  222. /* common functions */
  223. void print_help (void);
  224. void print_usage (void);
  225. /*** the various exit-states */
  226. /*enum {
  227. STATE_OK = 0,
  228. STATE_WARNING,
  229. STATE_CRITICAL,
  230. STATE_UNKNOWN,
  231. STATE_DEPENDANT,
  232. STATE_OOB
  233. };*/
  234. /* the strings that correspond to them */
  235. /*
  236. char *status_string[STATE_OOB] = {
  237. "OK",
  238. "WARNING",
  239. "CRITICAL",
  240. "UNKNOWN",
  241. "DEPENDANT"
  242. };
  243. */
  244. int status = STATE_OK;
  245. int fin_stat = STATE_OK;
  246. /*****************************************************************************
  247. * Code block start *
  248. *****************************************************************************/
  249. int main(int argc, char **argv)
  250. {
  251. int c;
  252. u_int lt, ht;
  253. int advance;
  254. struct protoent *proto;
  255. uid_t uid;
  256. struct host_name_list *host_ptr, *host_base_ptr;
  257. if(strchr(argv[0], '/')) prog = strrchr(argv[0], '/') + 1;
  258. else prog = argv[0];
  259. setlocale (LC_ALL, "");
  260. bindtextdomain (PACKAGE, LOCALEDIR);
  261. textdomain (PACKAGE);
  262. /* check if we are root */
  263. if(geteuid()) {
  264. printf(_("Root access needed (for raw sockets)\n"));
  265. exit(STATE_UNKNOWN);
  266. }
  267. /* confirm that ICMP is available on this machine */
  268. if((proto = getprotobyname("icmp")) == NULL)
  269. crash(_("icmp: unknown protocol"));
  270. /* create raw socket for ICMP calls (ping) */
  271. sock = socket(AF_INET, SOCK_RAW, proto->p_proto);
  272. if(sock < 0)
  273. crash(_("Can't create raw socket"));
  274. /* drop privileges now that we have the socket */
  275. if((uid = getuid())) {
  276. seteuid(uid);
  277. }
  278. if(argc < 2) print_usage();
  279. ident = getpid() & 0xFFFF;
  280. if(!(host_base_ptr = malloc(sizeof(struct host_name_list)))) {
  281. crash(_("Unable to allocate memory for host name list\n"));
  282. }
  283. host_ptr = host_base_ptr;
  284. backoff_flag = 0;
  285. opterr = 1;
  286. /* get command line options
  287. * -H denotes a host (actually ignored and picked up later)
  288. * -h for help
  289. * -V or -v for version
  290. * -d to display hostnames rather than addresses
  291. * -t sets timeout for packets and tcp connects
  292. * -r defines retries (persistence)
  293. * -p or -n sets packet count (5)
  294. * -b sets packet size (56)
  295. * -w sets warning threshhold (200,40%)
  296. * -c sets critical threshhold (500,80%)
  297. * -i sets interval for both packet transmissions and connect attempts
  298. */
  299. #define OPT_STR "amH:hvVDdAp:n:b:r:t:i:w:c:"
  300. while((c = getopt(argc, argv, OPT_STR)) != EOF) {
  301. switch (c) {
  302. case 'H':
  303. if(!(host_ptr->entry = malloc(strlen(optarg) + 1))) {
  304. crash(_("Failed to allocate memory for hostname"));
  305. }
  306. memset(host_ptr->entry, 0, strlen(optarg) + 1);
  307. host_ptr->entry = memcpy(host_ptr->entry, optarg, strlen(optarg));
  308. if(!(host_ptr->next = malloc(sizeof(struct host_name_list))))
  309. crash(_("Failed to allocate memory for hostname"));
  310. host_ptr = host_ptr->next;
  311. host_ptr->next = NULL;
  312. // add_name(optarg);
  313. break;
  314. /* this is recognized, but silently ignored.
  315. * host(s) are added later on */
  316. break;
  317. case 'w':
  318. if(get_threshold(optarg, &warn)) {
  319. printf(_("Illegal threshold pair specified for -%c"), c);
  320. print_usage();
  321. }
  322. break;
  323. case 'c':
  324. if(get_threshold(optarg, &crit)) {
  325. printf(_("Illegal threshold pair specified for -%c"), c);
  326. print_usage();
  327. }
  328. break;
  329. case 't':
  330. if(!(timeout = (u_int) strtoul(optarg, NULL, 0) * 100)) {
  331. printf(_("Option -%c requires integer argument\n"), c);
  332. print_usage();
  333. }
  334. break;
  335. case 'r':
  336. if(!(retry = (u_int) strtoul(optarg, NULL, 0))) {
  337. printf(_("Option -%c requires integer argument\n"), c);
  338. print_usage();
  339. }
  340. break;
  341. case 'i':
  342. if(!(interval = (u_int) strtoul(optarg, NULL, 0) * 100)) {
  343. printf(_("Option -%c requires positive non-zero integer argument\n"), c);
  344. print_usage();
  345. }
  346. break;
  347. case 'p':
  348. case 'n':
  349. if(!(count = (u_int) strtoul(optarg, NULL, 0))) {
  350. printf(_("Option -%c requires positive non-zero integer argument\n"), c);
  351. print_usage();
  352. }
  353. break;
  354. case 'b':
  355. if(!(ping_data_size = (u_int) strtoul(optarg, NULL, 0))) {
  356. printf(_("Option -%c requires integer argument\n"), c);
  357. print_usage();
  358. }
  359. break;
  360. case 'h':
  361. print_usage();
  362. break;
  363. case 'e':
  364. elapsed_flag = 1;
  365. break;
  366. case 'm':
  367. multif_flag = 1;
  368. break;
  369. case 'd':
  370. name_flag = 1;
  371. break;
  372. case 'A':
  373. addr_flag = 1;
  374. break;
  375. case 's':
  376. stats_flag = 1;
  377. break;
  378. case 'u':
  379. unreachable_flag = 1;
  380. break;
  381. case 'a':
  382. alive_flag = 1;
  383. break;
  384. case 'v':
  385. printf("%s: Version %s $Date$\n", prog, VERSION);
  386. printf("%s: comments to %s\n", prog, email);
  387. exit(STATE_OK);
  388. case 'g':
  389. /* use IP list generation */
  390. /* mutex with file input or command line targets */
  391. generate_flag = 1;
  392. break;
  393. default:
  394. printf(_("Option flag -%c specified, but not recognized\n"), c);
  395. print_usage();
  396. break;
  397. }
  398. }
  399. /* arguments are parsed, so now we validate them */
  400. if(count > 1) count_flag = 1;
  401. /* set threshold values to 10usec units (inherited from fping.c) */
  402. crit.rta = crit.rta / 10;
  403. warn.rta = warn.rta / 10;
  404. select_time = crit.rta;
  405. /* this isn't critical, but will most likely not be what the user expects
  406. * so we tell him/her about it, but keep running anyways */
  407. if(warn.pl > crit.pl || warn.rta > crit.rta) {
  408. select_time = warn.rta;
  409. printf("(WARNING threshold > CRITICAL threshold) :: ");
  410. fflush(stdout);
  411. }
  412. /* A timeout smaller than maximum rta threshold makes no sense */
  413. if(timeout < crit.rta) timeout = crit.rta;
  414. else if(timeout < warn.rta) timeout = warn.rta;
  415. if((interval < MIN_INTERVAL * 100 || retry > MAX_RETRY) && getuid()) {
  416. printf(_("%s: these options are too risky for mere mortals.\n"), prog);
  417. printf(_("%s: You need i >= %u and r < %u\n"),
  418. prog, MIN_INTERVAL, MAX_RETRY);
  419. printf(_("Current settings; i = %d, r = %d\n"),
  420. interval / 100, retry);
  421. print_usage();
  422. }
  423. if((ping_data_size > MAX_PING_DATA) || (ping_data_size < MIN_PING_DATA)) {
  424. printf(_("%s: data size %u not valid, must be between %u and %u\n"),
  425. prog, ping_data_size, MIN_PING_DATA, MAX_PING_DATA);
  426. print_usage();
  427. }
  428. if((backoff > MAX_BACKOFF_FACTOR) || (backoff < MIN_BACKOFF_FACTOR)) {
  429. printf(_("%s: backoff factor %.1f not valid, must be between %.1f and %.1f\n"),
  430. prog, backoff, MIN_BACKOFF_FACTOR, MAX_BACKOFF_FACTOR);
  431. print_usage();
  432. }
  433. if(count > MAX_COUNT) {
  434. printf(_("%s: count %u not valid, must be less than %u\n"),
  435. prog, count, MAX_COUNT);
  436. print_usage();
  437. }
  438. if(count_flag) {
  439. alive_flag = unreachable_flag = 0;
  440. }
  441. trials = (count > retry + 1) ? count : retry + 1;
  442. /* handle host names supplied on command line or in a file */
  443. /* if the generate_flag is on, then generate the IP list */
  444. argv = &argv[optind];
  445. /* cover allowable conditions */
  446. /* generate requires command line parameters beyond the switches */
  447. if(generate_flag && !*argv) {
  448. printf(_("Generate flag requires command line parameters beyond switches\n"));
  449. print_usage();
  450. }
  451. if(*argv && !generate_flag) {
  452. while(*argv) {
  453. if(!(host_ptr->entry = malloc(strlen(*argv) + 1))) {
  454. crash(_("Failed to allocate memory for hostname"));
  455. }
  456. memset(host_ptr->entry, 0, strlen(*argv) + 1);
  457. host_ptr->entry = memcpy(host_ptr->entry, *argv, strlen(*argv));
  458. if(!(host_ptr->next = malloc(sizeof(struct host_name_list))))
  459. crash(_("Failed to allocate memory for hostname"));
  460. host_ptr = host_ptr->next;
  461. host_ptr->next = NULL;
  462. // add_name(*argv);
  463. argv++;
  464. }
  465. }
  466. // now add all the hosts
  467. host_ptr = host_base_ptr;
  468. while(host_ptr->next) {
  469. add_name(host_ptr->entry);
  470. host_ptr = host_ptr->next;
  471. }
  472. if(!num_hosts) {
  473. printf(_("No hosts to work with!\n\n"));
  474. print_usage();
  475. }
  476. /* allocate array to hold outstanding ping requests */
  477. table = (HOST_ENTRY **) malloc(sizeof(HOST_ENTRY *) * num_hosts);
  478. if(!table) crash(_("Can't malloc array of hosts"));
  479. cursor = rrlist;
  480. for(num_jobs = 0; num_jobs < num_hosts; num_jobs++) {
  481. table[num_jobs] = cursor;
  482. cursor->i = num_jobs;
  483. cursor = cursor->next;
  484. } /* FOR */
  485. ping_pkt_size = ping_data_size + SIZE_ICMP_HDR;
  486. signal(SIGINT, (void *)finish);
  487. gettimeofday(&my_start_time, &tz);
  488. current_time = my_start_time;
  489. last_send_time.tv_sec = current_time.tv_sec - 10000;
  490. cursor = rrlist;
  491. advance = 0;
  492. /* main loop */
  493. while(num_jobs) {
  494. /* fetch all packets that receive within time boundaries */
  495. while(num_pingsent &&
  496. cursor &&
  497. cursor->num_sent > cursor->num_recv &&
  498. wait_for_reply(sock)) ;
  499. if(cursor && advance) {
  500. cursor = cursor->next;
  501. }
  502. gettimeofday(&current_time, &tz);
  503. lt = timeval_diff(&current_time, &last_send_time);
  504. ht = timeval_diff(&current_time, &cursor->last_send_time);
  505. advance = 1;
  506. /* if it's OK to send while counting or looping or starting */
  507. if(lt > interval) {
  508. /* send if starting or looping */
  509. if((cursor->num_sent == 0)) {
  510. send_ping(sock, cursor);
  511. continue;
  512. } /* IF */
  513. /* send if counting and count not exceeded */
  514. if(count_flag) {
  515. if(cursor->num_sent < count) {
  516. send_ping(sock, cursor);
  517. continue;
  518. } /* IF */
  519. } /* IF */
  520. } /* IF */
  521. /* is-it-alive mode, and timeout exceeded while waiting for a reply */
  522. /* and we haven't exceeded our retries */
  523. if((lt > interval) && !count_flag && !cursor->num_recv &&
  524. (ht > timeout) && (cursor->waiting < retry + 1)) {
  525. num_timeout++;
  526. /* try again */
  527. send_ping(sock, cursor);
  528. continue;
  529. } /* IF */
  530. /* didn't send, can we remove? */
  531. /* remove if counting and count exceeded */
  532. if(count_flag) {
  533. if((cursor->num_sent >= count)) {
  534. remove_job(cursor);
  535. continue;
  536. } /* IF */
  537. } /* IF */
  538. else {
  539. /* normal mode, and we got one */
  540. if(cursor->num_recv) {
  541. remove_job(cursor);
  542. continue;
  543. } /* IF */
  544. /* normal mode, and timeout exceeded while waiting for a reply */
  545. /* and we've run out of retries, so node is unreachable */
  546. if((ht > timeout) && (cursor->waiting >= retry + 1)) {
  547. num_timeout++;
  548. remove_job(cursor);
  549. continue;
  550. } /* IF */
  551. } /* ELSE */
  552. /* could send to this host, so keep considering it */
  553. if(ht > interval) {
  554. advance = 0;
  555. }
  556. } /* WHILE */
  557. finish();
  558. return 0;
  559. } /* main() */
  560. /************************************************************
  561. * Description:
  562. *
  563. * Main program clean up and exit point
  564. ************************************************************/
  565. void finish()
  566. {
  567. int i;
  568. HOST_ENTRY *h;
  569. gettimeofday(&my_end_time, &tz);
  570. /* tot up unreachables */
  571. for(i=0; i<num_hosts; i++) {
  572. h = table[i];
  573. if(!h->num_recv) {
  574. num_unreachable++;
  575. status = fin_stat = STATE_CRITICAL;
  576. if(num_hosts == 1) {
  577. printf("CRITICAL - %s is down (lost 100%%)|"
  578. "rta=;%d;%d;; pl=100%%;%d;%d;;\n",
  579. h->host,
  580. warn.rta / 100, crit.rta / 100,
  581. warn.pl, crit.pl);
  582. }
  583. else {
  584. printf(_("%s is down (lost 100%%)"), h->host);
  585. }
  586. }
  587. else {
  588. /* reset the status */
  589. status = STATE_OK;
  590. /* check for warning before critical, for debugging purposes */
  591. if(warn.rta <= h->total_time / h->num_recv) {
  592. /* printf("warn.rta exceeded\n");
  593. */ status = STATE_WARNING;
  594. }
  595. if(warn.pl <= ((h->num_sent - h->num_recv) * 100) / h->num_sent) {
  596. /* printf("warn.pl exceeded (pl=%d)\n",
  597. ((h->num_sent - h->num_recv) * 100) / h->num_sent);
  598. */ status = STATE_WARNING;
  599. }
  600. if(crit.rta <= h->total_time / h->num_recv) {
  601. /* printf("crit.rta exceeded\n");
  602. */ status = STATE_CRITICAL;
  603. }
  604. if(crit.pl <= ((h->num_sent - h->num_recv) * 100) / h->num_sent) {
  605. /* printf("crit.pl exceeded (pl=%d)\n",
  606. ((h->num_sent - h->num_recv) * 100) / h->num_sent);
  607. */ status = STATE_CRITICAL;
  608. }
  609. if(num_hosts == 1 || status != STATE_OK) {
  610. printf("%s - %s: rta %s ms, lost %d%%",
  611. state_text(status), h->host,
  612. sprint_tm(h->total_time / h->num_recv),
  613. h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0
  614. );
  615. /* perfdata only available for single-host stuff */
  616. if(num_hosts == 1) {
  617. printf("|rta=%sms;%d;%d;; pl=%d%%;%d;%d;;\n",
  618. sprint_tm(h->total_time / h->num_recv), warn.rta / 100, crit.rta / 100,
  619. h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0, warn.pl, crit.pl
  620. );
  621. }
  622. else printf(" :: ");
  623. }
  624. /* fin_stat should always hold the WORST state */
  625. if(fin_stat != STATE_CRITICAL && status != STATE_OK) {
  626. fin_stat = status;
  627. }
  628. }
  629. }
  630. if(num_noaddress) {
  631. printf(_("No hostaddress specified.\n"));
  632. print_usage();
  633. }
  634. else if(num_alive != num_hosts) {
  635. /* for future multi-check support */
  636. /*printf("num_alive != num_hosts (%d : %d)\n", num_alive, num_hosts);*/
  637. fin_stat = STATE_CRITICAL;
  638. }
  639. if(num_hosts > 1) {
  640. if(num_alive == num_hosts) {
  641. printf(_("OK - All %d hosts are alive\n"), num_hosts);
  642. }
  643. else {
  644. printf(_("CRITICAL - %d of %d hosts are alive\n"), num_alive, num_hosts);
  645. }
  646. }
  647. exit(fin_stat);
  648. }
  649. void send_ping(int lsock, HOST_ENTRY *h)
  650. {
  651. char *buffer;
  652. struct icmp *icp;
  653. PING_DATA *pdp;
  654. int n;
  655. buffer = (char *)malloc((size_t) ping_pkt_size);
  656. if(!buffer)
  657. crash(_("Can't malloc ping packet"));
  658. memset(buffer, 0, ping_pkt_size * sizeof(char));
  659. icp = (struct icmp *)buffer;
  660. gettimeofday(&h->last_send_time, &tz);
  661. icp->icmp_type = ICMP_ECHO;
  662. icp->icmp_code = 0;
  663. icp->icmp_cksum = 0;
  664. icp->icmp_seq = h->i;
  665. icp->icmp_id = ident;
  666. pdp = (PING_DATA *) (buffer + SIZE_ICMP_HDR);
  667. pdp->ping_ts = h->last_send_time;
  668. pdp->ping_count = h->num_sent;
  669. icp->icmp_cksum = in_cksum((u_short *) icp, ping_pkt_size);
  670. n = sendto(lsock, buffer, ping_pkt_size, 0,
  671. (struct sockaddr *)&h->saddr, sizeof(struct sockaddr_in));
  672. if(n < 0 || (unsigned int)n != ping_pkt_size) {
  673. if(unreachable_flag) {
  674. printf(_("%s error while sending ping: %s\n"),
  675. h->host, strerror(errno));
  676. } /* IF */
  677. num_unreachable++;
  678. remove_job(h);
  679. } /* IF */
  680. else {
  681. /* mark this trial as outstanding */
  682. h->resp_times[h->num_sent] = RESP_WAITING;
  683. h->num_sent++;
  684. h->waiting++;
  685. num_pingsent++;
  686. last_send_time = h->last_send_time;
  687. } /* ELSE */
  688. free(buffer);
  689. } /* send_ping() */
  690. int wait_for_reply(int lsock)
  691. {
  692. int result;
  693. static char buffer[4096];
  694. struct sockaddr_in response_addr;
  695. struct ip *ip;
  696. int hlen;
  697. struct icmp *icp;
  698. int n;
  699. HOST_ENTRY *h = NULL;
  700. long this_reply;
  701. int this_count;
  702. struct timeval sent_time;
  703. result = recvfrom_wto(lsock, buffer, sizeof(buffer),
  704. (struct sockaddr *)&response_addr, select_time);
  705. if(result < 0) return 0; /* timeout */
  706. ip = (struct ip *)buffer;
  707. #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ )
  708. /* The alpha headers are decidedly broken.
  709. * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
  710. * ip_v. So, to get ip_hl, we mask off the bottom four bits.
  711. */
  712. hlen = (ip->ip_vhl & 0x0F) << 2;
  713. #else
  714. hlen = ip->ip_hl << 2;
  715. #endif /* defined(__alpha__) && __STDC__ */
  716. if(result < hlen + ICMP_MINLEN) {
  717. printf(_("Received packet too short for ICMP (%d bytes from %s)\n"), result,
  718. inet_ntoa(response_addr.sin_addr));
  719. return (1); /* too short */
  720. } /* IF */
  721. icp = (struct icmp *)(buffer + hlen);
  722. if(icp->icmp_type != ICMP_ECHOREPLY) {
  723. /* handle some problem */
  724. if(handle_random_icmp(icp, &response_addr))
  725. num_othericmprcvd++;
  726. return 1;
  727. } /* IF */
  728. if(icp->icmp_id != ident)
  729. return 1; /* packet received, but not the one we are looking for! */
  730. num_pingreceived++;
  731. if(icp->icmp_seq >= (n_short) num_hosts)
  732. return(1); /* packet received, don't worry about it anymore */
  733. n = icp->icmp_seq;
  734. h = table[n];
  735. /* received ping is cool, so process it */
  736. gettimeofday(&current_time, &tz);
  737. h->waiting = 0;
  738. h->num_recv++;
  739. memcpy(&sent_time, icp->icmp_data + offsetof(PING_DATA, ping_ts),
  740. sizeof(sent_time));
  741. memcpy(&this_count, icp->icmp_data, sizeof(this_count));
  742. this_reply = timeval_diff(&current_time, &sent_time);
  743. h->total_time += this_reply;
  744. total_replies++;
  745. /* note reply time in array, probably */
  746. if((this_count >= 0) && ((unsigned int)this_count < trials)) {
  747. if(h->resp_times[this_count] != RESP_WAITING) {
  748. printf(_("%s : duplicate for [%d], %d bytes, %s ms"),
  749. h->host, this_count, result, sprint_tm(this_reply));
  750. if(response_addr.sin_addr.s_addr != h->saddr.sin_addr.s_addr)
  751. printf(" [<- %s]\n", inet_ntoa(response_addr.sin_addr));
  752. } /* IF */
  753. else h->resp_times[this_count] = this_reply;
  754. } /* IF */
  755. else {
  756. /* count is out of bounds?? */
  757. printf(_("%s : duplicate for [%d], %d bytes, %s ms\n"),
  758. h->host, this_count, result, sprint_tm(this_reply));
  759. } /* ELSE */
  760. if(h->num_recv == 1) {
  761. num_alive++;
  762. } /* IF */
  763. return num_jobs;
  764. } /* wait_for_reply() */
  765. int handle_random_icmp(struct icmp *p, struct sockaddr_in *addr)
  766. {
  767. struct icmp *sent_icmp;
  768. u_char *c;
  769. HOST_ENTRY *h;
  770. c = (u_char *) p;
  771. switch (p->icmp_type) {
  772. case ICMP_UNREACH:
  773. sent_icmp = (struct icmp *)(c + 28);
  774. if((sent_icmp->icmp_type == ICMP_ECHO) &&
  775. (sent_icmp->icmp_id == ident) &&
  776. (sent_icmp->icmp_seq < (n_short) num_hosts)) {
  777. /* this is a response to a ping we sent */
  778. h = table[sent_icmp->icmp_seq];
  779. if(p->icmp_code > ICMP_UNREACH_MAXTYPE) {
  780. printf(_("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s"),
  781. inet_ntoa(addr->sin_addr), h->host);
  782. } /* IF */
  783. else {
  784. printf(_("ICMP Unreachable from %s for ICMP Echo sent to %s"),
  785. inet_ntoa(addr->sin_addr), h->host);
  786. } /* ELSE */
  787. if(inet_addr(h->host) == INADDR_NONE)
  788. printf(" (%s)", inet_ntoa(h->saddr.sin_addr));
  789. printf("\n");
  790. } /* IF */
  791. return 1;
  792. case ICMP_SOURCEQUENCH:
  793. case ICMP_REDIRECT:
  794. case ICMP_TIMXCEED:
  795. case ICMP_PARAMPROB:
  796. sent_icmp = (struct icmp *)(c + 28);
  797. if((sent_icmp->icmp_type = ICMP_ECHO) &&
  798. (sent_icmp->icmp_id = ident) &&
  799. (sent_icmp->icmp_seq < (n_short) num_hosts)) {
  800. /* this is a response to a ping we sent */
  801. h = table[sent_icmp->icmp_seq];
  802. printf(_("ICMP Unreachable from %s for ICMP Echo sent to %s"),
  803. inet_ntoa(addr->sin_addr), h->host);
  804. if(inet_addr(h->host) == INADDR_NONE)
  805. printf(" (%s)", inet_ntoa(h->saddr.sin_addr));
  806. printf("\n");
  807. } /* IF */
  808. return 2;
  809. /* no way to tell whether any of these are sent due to our ping */
  810. /* or not (shouldn't be, of course), so just discard */
  811. case ICMP_TSTAMP:
  812. case ICMP_TSTAMPREPLY:
  813. case ICMP_IREQ:
  814. case ICMP_IREQREPLY:
  815. case ICMP_MASKREQ:
  816. case ICMP_MASKREPLY:
  817. default:
  818. return 0;
  819. } /* SWITCH */
  820. } /* handle_random_icmp() */
  821. int in_cksum(u_short * p, int n)
  822. {
  823. register u_short answer;
  824. register long sum = 0;
  825. u_short odd_byte = 0;
  826. while(n > 1) {
  827. sum += *p++;
  828. n -= 2;
  829. } /* WHILE */
  830. /* mop up an odd byte, if necessary */
  831. if(n == 1) {
  832. *(u_char *) (&odd_byte) = *(u_char *) p;
  833. sum += odd_byte;
  834. } /* IF */
  835. sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
  836. sum += (sum >> 16); /* add carry */
  837. answer = ~sum; /* ones-complement, truncate */
  838. return (answer);
  839. } /* in_cksum() */
  840. void add_name(char *name)
  841. {
  842. struct hostent *host_ent;
  843. int ipaddress;
  844. struct in_addr *ipa = (struct in_addr *)&ipaddress;
  845. struct in_addr *host_add;
  846. char *nm;
  847. int i = 0;
  848. if((ipaddress = inet_addr(name)) != -1) {
  849. /* input name is an IP addr, go with it */
  850. if(name_flag) {
  851. if(addr_flag)
  852. add_addr(name, na_cat(get_host_by_address(*ipa), *ipa), *ipa);
  853. else {
  854. nm = cpystr(get_host_by_address(*ipa));
  855. add_addr(name, nm, *ipa);
  856. } /* ELSE */
  857. } /* IF */
  858. else add_addr(name, name, *ipa);
  859. return;
  860. } /* IF */
  861. /* input name is not an IP addr, maybe it's a host name */
  862. host_ent = gethostbyname(name);
  863. if(host_ent == NULL) {
  864. if(h_errno == TRY_AGAIN) {
  865. u_sleep(DNS_TIMEOUT);
  866. host_ent = gethostbyname(name);
  867. } /* IF */
  868. if(host_ent == NULL) {
  869. printf(_("%s address not found\n"), name);
  870. num_noaddress++;
  871. return;
  872. } /* IF */
  873. } /* IF */
  874. host_add = (struct in_addr *)*(host_ent->h_addr_list);
  875. if(host_add == NULL) {
  876. printf(_("%s has no address data\n"), name);
  877. num_noaddress++;
  878. return;
  879. } /* IF */
  880. else {
  881. /* it is indeed a hostname with a real address */
  882. while(host_add) {
  883. if(name_flag && addr_flag)
  884. add_addr(name, na_cat(name, *host_add), *host_add);
  885. else if(addr_flag) {
  886. nm = cpystr(inet_ntoa(*host_add));
  887. add_addr(name, nm, *host_add);
  888. } /* ELSE IF */
  889. else {
  890. add_addr(name, name, *host_add);
  891. }
  892. if(!multif_flag) break;
  893. host_add = (struct in_addr *)(host_ent->h_addr_list[++i]);
  894. } /* WHILE */
  895. } /* ELSE */
  896. } /* add_name() */
  897. char *na_cat(char *name, struct in_addr ipaddr)
  898. {
  899. char *nm, *as;
  900. as = inet_ntoa(ipaddr);
  901. nm = (char *)malloc(strlen(name) + strlen(as) + 4);
  902. if(!nm)
  903. crash(_("Can't allocate some space for a string"));
  904. strcpy(nm, name);
  905. strcat(nm, " (");
  906. strcat(nm, as);
  907. strcat(nm, ")");
  908. return (nm);
  909. } /* na_cat() */
  910. void add_addr(char *name, char *host, struct in_addr ipaddr)
  911. {
  912. HOST_ENTRY *p;
  913. unsigned int n;
  914. int *i;
  915. if(!(p = (HOST_ENTRY *) malloc(sizeof(HOST_ENTRY)))) {
  916. crash(_("Can't allocate HOST_ENTRY"));
  917. }
  918. memset((char *)p, 0, sizeof(HOST_ENTRY));
  919. p->name = name;
  920. p->host = host;
  921. p->saddr.sin_family = AF_INET;
  922. p->saddr.sin_addr = ipaddr;
  923. p->running = 1;
  924. /* array for response time results */
  925. if(!(i = (int *)malloc(trials * sizeof(int)))) {
  926. crash(_("Can't allocate resp_times array"));
  927. }
  928. for(n = 1; n < trials; n++)
  929. i[n] = RESP_UNUSED;
  930. p->resp_times = i;
  931. if(!rrlist) {
  932. rrlist = p;
  933. p->next = p;
  934. p->prev = p;
  935. } /* IF */
  936. else {
  937. p->next = rrlist;
  938. p->prev = rrlist->prev;
  939. p->prev->next = p;
  940. p->next->prev = p;
  941. } /* ELSE */
  942. num_hosts++;
  943. } /* add_addr() */
  944. void remove_job(HOST_ENTRY * h)
  945. {
  946. h->running = 0;
  947. h->waiting = 0;
  948. num_jobs--;
  949. if(num_jobs) {
  950. /* remove us from list of active jobs */
  951. h->prev->next = h->next;
  952. h->next->prev = h->prev;
  953. if(h == cursor) cursor = h->next;
  954. } /* IF */
  955. else {
  956. cursor = NULL;
  957. rrlist = NULL;
  958. } /* ELSE */
  959. } /* remove_job() */
  960. char *get_host_by_address(struct in_addr in)
  961. {
  962. struct hostent *h;
  963. h = gethostbyaddr((char *)&in, sizeof(struct in_addr), AF_INET);
  964. if(h == NULL || h->h_name == NULL)
  965. return inet_ntoa(in);
  966. else
  967. return (char *)h->h_name;
  968. } /* get_host_by_address() */
  969. char *cpystr(char *string)
  970. {
  971. char *dst;
  972. if(string) {
  973. dst = (char *)malloc(1 + strlen(string));
  974. if(!dst) crash(_("malloc() failed!"));
  975. strcpy(dst, string);
  976. return dst;
  977. } /* IF */
  978. else return NULL;
  979. } /* cpystr() */
  980. void crash(char *msg)
  981. {
  982. if(errno || h_errno) {
  983. if(errno)
  984. printf("%s: %s : %s\n", prog, msg, strerror(errno));
  985. if(h_errno)
  986. printf(_("%s: %s : A network error occurred\n"), prog, msg);
  987. }
  988. else printf("%s: %s\n", prog, msg);
  989. exit(STATE_UNKNOWN);
  990. } /* crash() */
  991. long timeval_diff(struct timeval *a, struct timeval *b)
  992. {
  993. double temp;
  994. temp = (((a->tv_sec * 1000000) + a->tv_usec) -
  995. ((b->tv_sec * 1000000) + b->tv_usec)) / 10;
  996. return (long)temp;
  997. } /* timeval_diff() */
  998. char *sprint_tm(int t)
  999. {
  1000. static char buf[10];
  1001. /* <= 0.99 ms */
  1002. if(t < 100) {
  1003. sprintf(buf, "0.%02d", t);
  1004. return (buf);
  1005. } /* IF */
  1006. /* 1.00 - 9.99 ms */
  1007. if(t < 1000) {
  1008. sprintf(buf, "%d.%02d", t / 100, t % 100);
  1009. return (buf);
  1010. } /* IF */
  1011. /* 10.0 - 99.9 ms */
  1012. if(t < 10000) {
  1013. sprintf(buf, "%d.%d", t / 100, (t % 100) / 10);
  1014. return (buf);
  1015. } /* IF */
  1016. /* >= 100 ms */
  1017. sprintf(buf, "%d", t / 100);
  1018. return (buf);
  1019. } /* sprint_tm() */
  1020. /*
  1021. * select() is posix, so we expect it to be around
  1022. */
  1023. void u_sleep(int u_sec)
  1024. {
  1025. int nfound;
  1026. struct timeval to;
  1027. fd_set readset, writeset;
  1028. to.tv_sec = u_sec / 1000000;
  1029. to.tv_usec = u_sec - (to.tv_sec * 1000000);
  1030. /* printf("u_sleep :: to.tv_sec: %d, to_tv_usec: %d\n",
  1031. (int)to.tv_sec, (int)to.tv_usec);
  1032. */
  1033. FD_ZERO(&writeset);
  1034. FD_ZERO(&readset);
  1035. nfound = select(0, &readset, &writeset, NULL, &to);
  1036. if(nfound < 0)
  1037. crash(_("select() in u_sleep:"));
  1038. return;
  1039. } /* u_sleep() */
  1040. /************************************************************
  1041. * Description:
  1042. *
  1043. * receive with timeout
  1044. * returns length of data read or -1 if timeout
  1045. * crash on any other errrors
  1046. ************************************************************/
  1047. /* TODO: add MSG_DONTWAIT to recvfrom flags (currently 0) */
  1048. int recvfrom_wto(int lsock, char *buf, int len, struct sockaddr *saddr, int timo)
  1049. {
  1050. int nfound = 0, slen, n;
  1051. struct timeval to;
  1052. fd_set readset, writeset;
  1053. to.tv_sec = timo / 1000000;
  1054. to.tv_usec = (timo - (to.tv_sec * 1000000)) * 10;
  1055. /* printf("to.tv_sec: %d, to.tv_usec: %d\n", (int)to.tv_sec, (int)to.tv_usec);
  1056. */
  1057. FD_ZERO(&readset);
  1058. FD_ZERO(&writeset);
  1059. FD_SET(lsock, &readset);
  1060. nfound = select(lsock + 1, &readset, &writeset, NULL, &to);
  1061. if(nfound < 0) crash(_("select() in recvfrom_wto"));
  1062. if(nfound == 0) return -1; /* timeout */
  1063. if(nfound) {
  1064. slen = sizeof(struct sockaddr);
  1065. n = recvfrom(sock, buf, len, 0, saddr, &slen);
  1066. if(n < 0) crash(_("recvfrom"));
  1067. return(n);
  1068. }
  1069. return(0); /* 0 bytes read, so return it */
  1070. } /* recvfrom_wto() */
  1071. /*
  1072. * u = micro
  1073. * m = milli
  1074. * s = seconds
  1075. */
  1076. int get_threshold(char *str, threshold *th)
  1077. {
  1078. unsigned int i, factor = 0;
  1079. char *p = NULL;
  1080. if(!str || !strlen(str) || !th) return -1;
  1081. for(i=0; i<strlen(str); i++) {
  1082. /* we happily accept decimal points in round trip time thresholds,
  1083. * but we ignore them quite blandly. The new way of specifying higher
  1084. * precision is to specify 'u' (for microseconds),
  1085. * 'm' (for millisecs - default) or 's' for seconds. */
  1086. if(!p && !factor) {
  1087. if(str[i] == 's') factor = 1000000; /* seconds */
  1088. else if(str[i] == 'm') factor = 1000; /* milliseconds */
  1089. else if(str[i] == 'u') factor = 1; /* microseconds */
  1090. }
  1091. if(str[i] == '%') str[i] = '\0';
  1092. else if(str[i] == ',' && !p && i != (strlen(str) - 1)) {
  1093. p = &str[i+1];
  1094. str[i] = '\0';
  1095. }
  1096. }
  1097. /* default to milliseconds */
  1098. if(!factor) factor = 1000;
  1099. if(!p || !strlen(p)) return -1;
  1100. th->rta = (unsigned int)strtoul(str, NULL, 0) * factor;
  1101. th->pl = (unsigned int)strtoul(p, NULL, 0);
  1102. return 0;
  1103. }
  1104. void
  1105. print_help (void)
  1106. {
  1107. print_revision (progname, revision);
  1108. printf ("Copyright (c) 2004 Andreas Ericsson <ae@op5.se>\n");
  1109. printf (COPYRIGHT, copyright, email);
  1110. printf (_("This plugin will check hosts sending icmp pings\n\n"));
  1111. print_usage ();
  1112. printf (_(UT_HELP_VRSN));
  1113. printf (_("\
  1114. -H, \n\
  1115. Host name argument for servers\n\
  1116. -b \n\
  1117. ping packet size in bytes (default %d)\n\
  1118. -n \n\
  1119. number of pings to send to each target (default %d)\n\
  1120. -r \n\
  1121. number of retries (default %d)\n\
  1122. -t \n\
  1123. timeout value (in msec) (default %d)\n\
  1124. -i \n\
  1125. packet interval (in msec) (default %d)\n\
  1126. -w \n\
  1127. warning threshold pair, given as RTA[ums],PL[%%]\n\
  1128. -c \n\
  1129. critical threshold pair, given as RTA[ums],PL[%%]\n\
  1130. -D \n\
  1131. increase debug output level\n\n"),ping_data_size,count,retry,(timeout / 100),DEFAULT_INTERVAL);
  1132. printf (_(UT_WARN_CRIT));
  1133. printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
  1134. printf (_(UT_VERBOSE));
  1135. // printf (_("This plugin will check hosts sending icmp pings\n"));
  1136. printf (_(UT_SUPPORT));
  1137. }
  1138. void
  1139. print_usage (void)
  1140. {
  1141. printf ("\
  1142. Usage: %s -H <vhost> | [-b <ping packet size in bytes>] [-n <number of pings>]\n\
  1143. [-r <number of retries>] [-t <timeout>] [-i packet interval]\n\
  1144. [-w <warning threshold>] [-c <critical threshold>]\n\
  1145. [-D <debug>] \n", progname);
  1146. }