home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / fping / part01 < prev    next >
Encoding:
Text File  |  1993-07-02  |  42.2 KB  |  1,395 lines

  1. Newsgroups: comp.sources.unix
  2. From: schemers@Slapshot.Stanford.EDU (Roland J. Schemers III)
  3. Subject: v26i278: fping - A tool to quickly ping N number of hosts, Part01/01
  4. Sender: unix-sources-moderator@gw.home.vix.com
  5. Approved: vixie@gw.home.vix.com
  6.  
  7. Submitted-By: schemers@Slapshot.Stanford.EDU (Roland J. Schemers III)
  8. Posting-Number: Volume 26, Issue 278
  9. Archive-Name: fping/part01
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of shell archive."
  18. # Contents:  README CHANGES fping.c fping.man Makefile README.VMS
  19. # Wrapped by schemers@Slapshot.Stanford.EDU on Mon Feb 22 16:19:25 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'README' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'README'\"
  23. else
  24. echo shar: Extracting \"'README'\" \(2334 characters\)
  25. sed "s/^X//" >'README' <<'END_OF_FILE'
  26. X
  27. X        fping - A tool to quickly ping N number of hosts to determine
  28. X        their reachability without flooding the network.
  29. X
  30. X             Roland J. Schemers III - Stanford University
  31. X                   schemers@Slapshot.Stanford.EDU
  32. X
  33. X      fping is a ping(1) like program which uses the Internet Control
  34. X      Message Protocol (ICMP) echo request to determine if a host is
  35. X      up. fping is different from ping in that you can specify any
  36. X      number of hosts on the command line, or specify a file containing
  37. X      the lists of hosts to ping. Instead of trying one host until it
  38. X      timeouts or replies, fping will send out a ping packet and move
  39. X      on to the next host in a round-robin fashion. If a host replies,
  40. X      it is noted and removed from the list of hosts to check. If a host
  41. X      does not respond within a certain time limit and/or retry limit it 
  42. X      will be considered unreachable. 
  43. X
  44. XSite
  45. X      Stanford University has a large TCP/IP network with over 12,000 
  46. X      assigned IP addresses and over 100 IP subnets.
  47. X
  48. XProblem and Issues
  49. X
  50. X      With a large a number of IP addresses in use, its becomes more and
  51. X      more time consuming to check on which IP addresses are actively
  52. X      in use, and which critical machines (routers, bridges, servers, etc)
  53. X      are reachable. One example is we have a program which goes through
  54. X      all of our routers arp caches looking for IP addresses that are in 
  55. X      use. After finding a list of IP addresses that aren't in any arp
  56. X      caches fping can then be used to see if these IP addresses really
  57. X      aren't being used, or are just behind the routers. Checking 2500
  58. X      hosts (99% of which are unreachable) via ping can take hours.
  59. X       
  60. XSolution
  61. X      
  62. X       fping was written to solve the problem of pinging N number of hosts
  63. X       in an efficient manner. By sending out pings in a round-robin fashion
  64. X       and checking on responses as they come in at random, a large number of 
  65. X       hosts can be checked at once. Checking 2500 hosts (5 packets per host, 
  66. X       10 msec between ping packets) takes under 3 minutes. Also, using fping
  67. X       to check 30 routers that are currently reachable takes about 420
  68. X       milliseconds (elapsed real time).
  69. X
  70. X       Unlike ping, fping is meant to be used in scripts and its
  71. X       output is easy to parse.
  72. END_OF_FILE
  73. if test 2334 -ne `wc -c <'README'`; then
  74.     echo shar: \"'README'\" unpacked with wrong size!
  75. fi
  76. # end of 'README'
  77. fi
  78. if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  79.   echo shar: Will not clobber existing file \"'CHANGES'\"
  80. else
  81. echo shar: Extracting \"'CHANGES'\" \(2952 characters\)
  82. sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
  83. X* Revision 1.20  1993/02/23  00:16:38  schemers
  84. X
  85. Xfixed syntax error (should have compiled before checking in...)
  86. X
  87. X* Revision 1.19  1993/02/23  00:15:15  schemers
  88. X
  89. Xturned off printing of "is alive" when -a is specified.
  90. X
  91. X* Revision 1.18  1992/07/28  15:16:44  schemers
  92. X
  93. Xadded a fflush(stdout) call before the summary is sent to stderr, so
  94. Xeverything shows up in the right order.
  95. X
  96. X* Revision 1.17  1992/07/23  03:29:42  schemers
  97. X* Revision 1.16  1992/07/22  19:24:37  schemers
  98. X
  99. XFixed declaration of timeval_diff. Didn't notice the problem because
  100. XI use 'cc' in stead of gcc under Ultrix. Time to switch? :-)
  101. X
  102. XModified file reaing so it would skip blank lines or lines starting
  103. Xwith a '#'. Now you can do something like:
  104. X
  105. Xfping -ad < /etc/hosts
  106. X
  107. X* Revision 1.15  1992/07/21  17:07:18  schemers
  108. X
  109. XPut in sanity checks so only root can specify "dangerous" options.
  110. XChanged usage to show switchs in alphabetical order.
  111. X* Revision 1.14  1992/07/21  16:40:52  schemers
  112. X* Revision 1.13  1992/07/17  21:02:17  schemers
  113. X
  114. XChanged the default timeout to 2500 msec, and retry to 3. This was
  115. Xdue to suggestions from people with slow (WAN) networks. The default
  116. X1 sec timeout was too fast.
  117. X
  118. X
  119. XAdded '-e' option for showing elapsed (round-trip) times on pakets, and
  120. Xmodified the -s option to include min, max, and average round-trip times,
  121. Xand over all elapsed time.
  122. X
  123. XModified action taken when a error is returned from sendto. The action
  124. Xtaken now considers the host unreachable and prints the hostname 
  125. Xfollowed by the errno message. The program will not exit and will continue
  126. Xto try other hosts.
  127. X
  128. X* Revision 1.12  1992/07/17  16:38:54  schemers
  129. X* Revision 1.11  1992/07/17  16:28:38  schemers
  130. X
  131. X move socket create call so I could do a setuid(getuid()) before the
  132. X fopen call is made. Once the socket is created root privs aren't needed
  133. X to send stuff out on it.
  134. X
  135. X moved num_timeout counter. It really was for debug purposes and didn't
  136. X make sense to the general public :-) Now it is the number of timeouts
  137. X (pings that didn't get received with the time limit).
  138. X
  139. X
  140. X* Revision 1.10 1992/07/16  16:24:38  schemers
  141. X* Revision 1.9  1992/07/16  16:00:04  schemers
  142. X* Revision 1.8  1992/07/16  05:44:41  schemers
  143. X
  144. XAdded _NO_PROTO stuff for older compilers, and _POSIX_SOURCE
  145. Xfor unistd.h, and _POSIX_SOURCE for stdlib.h. Also added
  146. Xcheck for __cplusplus.
  147. X
  148. XNow compiles ok under Ultrix 3.1, and Sun4 using cc. Also compiled
  149. Xok using g++ 2.2.2.
  150. X
  151. XChanged '-a' and '-u' flags to be mutually exclusive (makes sense, since
  152. Xspecifiying both '-a' and '-u' is the same as not specifiying anything.
  153. XSince '-a' and '-u' are mutually exclusive, these options now only print
  154. Xthe hostname, and not the 'is alive' or 'is unreachable'  messages.
  155. XThis makes it much easier to do stuff like:
  156. X
  157. X#!/usr/local/bin/perl
  158. X$hosts_to_backup=`cat /etc/hosts.backup|fping -a`;
  159. X
  160. XSince you don't have to strip off the 'is alive' messages.
  161. X
  162. XChanged usage to and stats to print to stderr instead of stdout.
  163. X
  164. X
  165. END_OF_FILE
  166. if test 2952 -ne `wc -c <'CHANGES'`; then
  167.     echo shar: \"'CHANGES'\" unpacked with wrong size!
  168. fi
  169. # end of 'CHANGES'
  170. fi
  171. if test -f 'fping.c' -a "${1}" != "-c" ; then 
  172.   echo shar: Will not clobber existing file \"'fping.c'\"
  173. else
  174. echo shar: Extracting \"'fping.c'\" \(23070 characters\)
  175. sed "s/^X//" >'fping.c' <<'END_OF_FILE'
  176. X/* 
  177. X * fping: fast-ping, file-ping
  178. X *
  179. X * Used to send out ping requests to a list of hosts in a round robin
  180. X * fashion. 
  181. X *
  182. X *
  183. X *   fping has been compiled tested under the following systems:
  184. X *
  185. X *  Ultrix 4.2a DECstation
  186. X *  Ultrix 3.1 VAX
  187. X *  NeXT 2.1
  188. X *  SunOS 4.1.1 Sparcstation (gcc and cc)
  189. X *  AIX 3.1 RISC System/6000
  190. X *
  191. X */
  192. X
  193. X/* 
  194. X ***************************************************
  195. X *
  196. X * Standard RCS Header information (see co(1))
  197. X *
  198. X * $Author: schemers $
  199. X *
  200. X * $Date: 1993/02/23 00:16:38 $
  201. X *
  202. X * $Revision: 1.20 $
  203. X *
  204. X * $Locker: schemers $
  205. X *
  206. X * $Source: /networking/src/fping/RCS/fping.c,v $
  207. X *
  208. X * $State: Exp $
  209. X *
  210. X * $Log: fping.c,v $
  211. X * Revision 1.20  1993/02/23  00:16:38  schemers
  212. X * fixed syntax error (should have compiled before checking in...)
  213. X *
  214. X * Revision 1.19  1993/02/23  00:15:15  schemers
  215. X * turned off printing of "is alive" when -a is specified.
  216. X *
  217. X * Revision 1.18  1992/07/28  15:16:44  schemers
  218. X * added a fflush(stdout) call before the summary is sent to stderr, so
  219. X * everything shows up in the right order.
  220. X *
  221. X * Revision 1.17  1992/07/23  03:29:42  schemers
  222. X * fixed declaration of timeval_diff.
  223. X *
  224. X * Revision 1.16  1992/07/22  19:24:37  schemers
  225. X * Modified file reading so it would skip blanks lines or lines starting
  226. X * with a '#'. Now you can do something like:
  227. X *
  228. X * fping -ad < /etc/hosts
  229. X *
  230. X * Revision 1.15  1992/07/21  17:07:18  schemers
  231. X * Put in sanity checks so only root can specify "dangerous" options.
  232. X * Changed usage to show switchs in alphabetical order.
  233. X *
  234. X * Revision 1.14  1992/07/21  16:40:52  schemers
  235. X * Now when sendto returns an error, the host is considered unreachable and
  236. X * and the error message (from errno) is displayed.
  237. X *
  238. X * Revision 1.13  1992/07/17  21:02:17  schemers
  239. X * changed default timeout to 2500 msec (for WANs), and default try
  240. X * to 3. This gives 10 second overall timeout.
  241. X *
  242. X * Added -e option for showing elapsed (round-trip) time on packets
  243. X *
  244. X * Modified -s option to inlude to round-trip stats
  245. X *
  246. X * Added #ifndef DEFAULT_* stuff its easier to change the defaults
  247. X *
  248. X * Reorganized main loop.
  249. X *
  250. X * cleaned up timeval stuff. removed set_timeval and timeval_expired
  251. X * since they aren't needed anymore. Just use timeval_diff.
  252. X *
  253. X * Revision 1.12  1992/07/17  16:38:54  schemers
  254. X * move socket create call so I could do a setuid(getuid()) before the
  255. X * fopen call is made. Once the socket is created root privs aren't needed
  256. X * to send stuff out on it.
  257. X *
  258. X * Revision 1.11  1992/07/17  16:28:38  schemers
  259. X * moved num_timeout counter. It really was for debug purposes and didn't
  260. X * make sense to the general public :-) Now it is the number of timeouts
  261. X * (pings that didn't get received with the time limit).
  262. X *
  263. X * Revision 1.10  1992/07/16  16:24:38  schemers
  264. X * changed usage() to use fprintf(stderr,"...");
  265. X *
  266. X * Revision 1.9  1992/07/16  16:00:04  schemers
  267. X * Added _NO_PROTO stuff for older compilers, and _POSIX_SOURCE
  268. X * for unistd.h, and _POSIX_SOURCE for stdlib.h. Also added
  269. X * check for __cplusplus.
  270. X *
  271. X * Revision 1.8  1992/07/16  05:44:41  schemers
  272. X * changed -a and -u to only show hostname in results. This is
  273. X * for easier parsing. Also added -v flag
  274. X *
  275. X * Revision 1.7  1992/07/14  18:45:23  schemers
  276. X * initialized last_time in add_host function
  277. X *
  278. X * Revision 1.6  1992/07/14  18:32:40  schemers
  279. X * changed select to use FD_ macros
  280. X *
  281. X * Revision 1.5  1992/07/14  17:21:22  schemers
  282. X * standardized exit status codes
  283. X *
  284. X * Revision 1.4  1992/06/26  15:25:35  schemers
  285. X * changed name from rrping to fping
  286. X *
  287. X * Revision 1.3  1992/06/24  15:39:32  schemers
  288. X * added -d option for unreachable systems
  289. X *
  290. X * Revision 1.2  1992/06/23  03:01:23  schemers
  291. X * misc fixes from R.L. "Bob" Morgan
  292. X *
  293. X * Revision 1.1  1992/06/19  18:23:52  schemers
  294. X * Initial revision
  295. X *
  296. X *--------------------------------------------------
  297. X * Copyright (c) 1992 Board of Trustees
  298. X *            Leland Stanford Jr. University
  299. X ***************************************************
  300. X */
  301. X
  302. X/*
  303. X * Redistribution and use in source and binary forms are permitted
  304. X * provided that the above copyright notice and this paragraph are
  305. X * duplicated in all such forms and that any documentation,
  306. X * advertising materials, and other materials related to such
  307. X * distribution and use acknowledge that the software was developed
  308. X * by Stanford University.  The name of the University may not be used 
  309. X * to endorse or promote products derived from this software without 
  310. X * specific prior written permission.
  311. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  312. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  313. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  314. X */
  315. X
  316. X#ifndef _NO_PROTO
  317. X#if !__STDC__ && !defined(__cplusplus) && !defined(FUNCPROTO) \
  318. X                                                 && !defined(_POSIX_SOURCE)
  319. X#define _NO_PROTO
  320. X#endif /* __STDC__ */
  321. X#endif /* _NO_PROTO */
  322. X
  323. X#ifdef __cplusplus
  324. Xextern "C" {
  325. X#endif
  326. X
  327. X#include <stdio.h>
  328. X#include <errno.h>
  329. X#include <time.h>
  330. X
  331. X#ifdef _POSIX_SOURCE
  332. X#include <unistd.h>
  333. X#endif
  334. X
  335. X#ifdef __STDC__
  336. X#include <stdlib.h>
  337. X#endif
  338. X
  339. X#include <string.h>
  340. X
  341. X#include <sys/types.h>
  342. X#include <sys/time.h>
  343. X#include <sys/socket.h>
  344. X
  345. X
  346. X#include <netinet/in_systm.h>
  347. X#include <netinet/in.h>
  348. X#include <netinet/ip.h>
  349. X#include <netinet/ip_icmp.h>
  350. X#include <arpa/inet.h>
  351. X
  352. X#include <netdb.h>
  353. X
  354. X/* RS6000 has sys/select.h */
  355. X#ifndef FD_SET
  356. X#include <sys/select.h>
  357. X#endif
  358. X
  359. X/* externals */
  360. X
  361. Xextern char *optarg;
  362. Xextern int optind,opterr;
  363. Xextern char *sys_errlist[];
  364. X
  365. X
  366. X#ifdef __cplusplus
  367. X}
  368. X#endif
  369. X
  370. X/* constants */
  371. X
  372. X#ifndef DEFAULT_INTERVAL
  373. X#define DEFAULT_INTERVAL 25        /* default time between packets (msec) */
  374. X#endif
  375. X
  376. X#ifndef DEFAULT_TIMEOUT
  377. X#define DEFAULT_TIMEOUT 2500       /* individual host timeouts */
  378. X#endif
  379. X
  380. X#ifndef DEFAULT_RETRY 
  381. X#define DEFAULT_RETRY 3            /* number of times to retry a host */
  382. X#endif
  383. X
  384. X
  385. X/* typedef's */
  386. X
  387. X/* entry used to keep track of each host we are pinging */
  388. X
  389. Xtypedef struct host_entry {
  390. X     char                 *host;              /* text description of host */
  391. X     struct sockaddr_in   saddr;              /* internet address */
  392. X     int                  i;                  /* index into array */
  393. X     int                  num_packets_sent;   /* number of ping packets sent */
  394. X     struct host_entry    *prev,*next;        /* doubly linked list */
  395. X     struct timeval       last_time;          /* time of last packet sent */
  396. X} HOST_ENTRY;
  397. X
  398. X/* globals */
  399. X
  400. XHOST_ENTRY *rrlist=NULL;    /* linked list of hosts be pinged */
  401. XHOST_ENTRY **table=NULL;    /* array of pointers to items in the list */
  402. XHOST_ENTRY *cursor;
  403. X
  404. Xchar *prog;
  405. Xint ident;                  /* our pid */
  406. Xint s;                      /* socket */
  407. X
  408. Xint retry = DEFAULT_RETRY;
  409. Xint timeout = DEFAULT_TIMEOUT;
  410. Xint interval = DEFAULT_INTERVAL;
  411. X
  412. Xlong max_reply=0;
  413. Xlong min_reply=10000;
  414. Xint total_replies=0;
  415. Xdouble sum_replies=0;
  416. X
  417. Xstruct timeval timeout_timeval;
  418. Xstruct timezone tz;
  419. X
  420. Xint num_waiting=0;                 /* number of hosts we are pinging */
  421. Xint num_hosts;                     /* total number of hosts */
  422. X
  423. Xint num_alive=0,                  /* total number alive */
  424. X    num_unreachable=0,            /* total number unreachable */
  425. X    num_noaddress=0;              /* total number of addresses not found */
  426. X
  427. Xint num_timeout=0,                /* number of times select timed out */
  428. X    num_pingsent=0,               /* total pings sent */
  429. X    num_pingreceived=0;           /* total pings received */
  430. X
  431. Xstruct timeval current_time;      /* current time (pseudo) */
  432. Xstruct timeval start_time; 
  433. Xstruct timeval end_time;   
  434. X
  435. X/* switches */
  436. Xint verbose_flag,dns_flag,stats_flag,unreachable_flag,alive_flag;
  437. Xint elapsed_flag,version_flag;
  438. X
  439. Xchar *filename=NULL;               /* file containing hosts to ping */
  440. X
  441. X/* forward declarations */
  442. X
  443. X#ifdef _NO_PROTO
  444. X
  445. Xvoid add_host();
  446. Xvoid crash_and_burn();
  447. Xvoid errno_crash_and_burn();
  448. Xchar *get_host_by_address();
  449. Xint in_cksum();
  450. Xint recvfrom_wto ();
  451. Xvoid remove_job();
  452. Xvoid send_ping();
  453. Xvoid usage();
  454. Xint wait_for_reply();
  455. Xlong timeval_diff();
  456. X#else
  457. X
  458. Xvoid add_host(char *host);
  459. Xvoid crash_and_burn(char *message);
  460. Xvoid errno_crash_and_burn(char *message);
  461. Xchar *get_host_by_address(struct in_addr in);
  462. Xint in_cksum(u_short *p, int n);
  463. Xint recvfrom_wto (int s, char *buf, int len, struct sockaddr *saddr, int timo);
  464. Xvoid remove_job(HOST_ENTRY *h);
  465. Xvoid send_ping(int s,HOST_ENTRY *h);
  466. Xlong timeval_diff(struct timeval *a,struct timeval *b);
  467. Xvoid usage();
  468. Xint wait_for_reply();
  469. X
  470. X#endif
  471. X
  472. X#ifdef _NO_PROTO
  473. Xint main(argc,argv)
  474. Xint argc; char **argv;
  475. X#else
  476. Xint main(int argc, char **argv)
  477. X#endif
  478. X{
  479. X
  480. X  int c;
  481. X
  482. X  struct protoent *proto;
  483. X
  484. X  /* check if we are root */
  485. X
  486. X  if (geteuid()) {
  487. X      fprintf(stderr,
  488. X        "This program can only be run by root, or it must be setuid root.\n");
  489. X      exit(3);
  490. X  }
  491. X
  492. X  if ((proto = getprotobyname("icmp")) == NULL) 
  493. X             crash_and_burn("icmp: unknown protocol");
  494. X
  495. X  /* create the socket here as root. Then setuid back to 
  496. X        the person running the program. This is so they
  497. X        can't open a file that doesn't belong to them! */
  498. X
  499. X  s = socket(AF_INET, SOCK_RAW, proto->p_proto);
  500. X  if (s<0) errno_crash_and_burn("can't create raw socket");
  501. X
  502. X  setuid(getuid());
  503. X
  504. X  prog = argv[0];
  505. X  ident = getpid() & 0xFFFF;
  506. X
  507. X  verbose_flag=1;
  508. X
  509. X  opterr=0;
  510. X
  511. X  while ((c = getopt(argc,argv,"edhqusavt:i:f:r:")) != EOF) 
  512. X     switch (c) {
  513. X       case 't': if ( (timeout=atoi(optarg)) <0) usage();  break;
  514. X       case 'f': filename= optarg;                         break;
  515. X       case 'r': if ((retry=atoi(optarg))<0) usage();      break;
  516. X       case 'i': if ((interval=atoi(optarg))<0) usage();   break;
  517. X       case 'h': usage();                                  break;
  518. X       case 'q': verbose_flag = 0;                           break;
  519. X       case 'e': elapsed_flag = 1;                           break;
  520. X       case 'd': dns_flag = 1;                             break;
  521. X       case 's': stats_flag = 1;                           break;
  522. X       case 'u': unreachable_flag = 1;                     break;
  523. X       case 'a': alive_flag = 1;                           break;
  524. X           case 'v':
  525. X                     printf("%s: $Revision: 1.20 $ $Date: 1993/02/23 00:16:38 $\n",argv[0]);
  526. X                     printf("%s: comments to schemers@Stanford.EDU\n",argv[0]);
  527. X                     exit(0);
  528. X           default : fprintf(stderr,"Unknown flag: %s\n",argv[0]); 
  529. X                     usage(); break;
  530. X     }
  531. X
  532. X  if (unreachable_flag && alive_flag) {
  533. X    fprintf(stderr,"%s: specify only one of a,u\n",argv[0]);
  534. X    usage();
  535. X  }
  536. X
  537. X  if ( (interval<10 || retry >20 || timeout <250) && getuid()) {
  538. X    fprintf(stderr,"%s: these options are too risky for mere mortals.\n",prog);
  539. X    fprintf(stderr,"%s: You need i >=10, retry < 20, and t >= 250\n",prog);
  540. X    exit(3);
  541. X  }
  542. X
  543. X  if (alive_flag || unreachable_flag) verbose_flag=0;
  544. X
  545. X  argv = &argv[optind];
  546. X  if (*argv && filename)   { usage(); }
  547. X  if (!*argv && !filename) { filename = "-"; }
  548. X
  549. X  if (*argv) while (*argv) {
  550. X             add_host(*argv);
  551. X             ++argv;
  552. X  } else if (filename) {
  553. X         FILE *ping_file;
  554. X         char line[132];
  555. X         char host[132],*p;
  556. X         if (strcmp(filename,"-")==0) {
  557. X             ping_file=fdopen(0,"r");
  558. X         } else {
  559. X             ping_file=fopen(filename,"r");
  560. X         }
  561. X         if (!ping_file) errno_crash_and_burn("fopen");
  562. X         while(fgets(line,132,ping_file)) {
  563. X           sscanf(line,"%s",host);
  564. X              if ((!*host) || (host[0]=='#'))  /* magic to avoid comments */
  565. X                continue;
  566. X           p=(char*)malloc(strlen(host)+1);
  567. X           if (!p) crash_and_burn("can't malloc host");
  568. X           strcpy(p,host);
  569. X           add_host(p);
  570. X         }
  571. X         fclose(ping_file);
  572. X  } else usage();
  573. X
  574. X  if (!num_hosts) exit(2);
  575. X
  576. X  /* allocate array to hold outstanding ping requests */
  577. X
  578. X  table = (HOST_ENTRY **) malloc(sizeof(HOST_ENTRY *)*num_hosts);
  579. X  if (!table) crash_and_burn("Can't malloc array of hosts");
  580. X
  581. X  cursor=rrlist;
  582. X
  583. X  for( num_waiting=0; num_waiting < num_hosts; num_waiting++ ) {
  584. X      table[num_waiting]=cursor;
  585. X      cursor->i = num_waiting;
  586. X      cursor=cursor->next;
  587. X  }
  588. X
  589. X  gettimeofday(&start_time,&tz);
  590. X  cursor=rrlist;
  591. X  while (num_waiting) {  /* while pings are outstanding */
  592. X        if ( (timeval_diff(¤t_time,&cursor->last_time)> timeout) ||
  593. X                                                cursor->num_packets_sent==0)  {
  594. X           if (cursor->num_packets_sent>0)  num_timeout++;
  595. X            if (cursor->num_packets_sent == retry+1) {
  596. X                        if(verbose_flag || unreachable_flag) {
  597. X                              if (dns_flag) printf("%s",
  598. X                                 get_host_by_address(cursor->saddr.sin_addr));
  599. X                              else    printf("%s",cursor->host);
  600. X                              if (verbose_flag) printf(" is unreachable");
  601. X                              printf("\n");
  602. X                       }
  603. X                       num_unreachable++;
  604. X                       remove_job(cursor); 
  605. X           } else send_ping(s,cursor);
  606. X     }
  607. X      while(wait_for_reply() && num_waiting) {  /* call wfr until we timeout */
  608. X                    /* wait! */
  609. X      }
  610. X      gettimeofday(¤t_time,&tz);
  611. X      if (cursor) cursor = cursor->next;
  612. X  }  
  613. X
  614. X  gettimeofday(&end_time,&tz);
  615. X
  616. X  if (stats_flag) {
  617. X     fflush(stdout);
  618. X     fprintf(stderr,"\n");
  619. X     fprintf(stderr," %8d hosts\n",num_hosts);
  620. X     fprintf(stderr," %8d alive\n",num_alive);
  621. X     fprintf(stderr," %8d unreachable\n",num_unreachable);
  622. X     fprintf(stderr," %8d unknown addresses\n",num_noaddress);
  623. X     fprintf(stderr,"\n");
  624. X     fprintf(stderr," %8d timeouts (waiting for response)\n",num_timeout);
  625. X     fprintf(stderr," %8d pings sent\n",num_pingsent);
  626. X     fprintf(stderr," %8d pings received\n",num_pingreceived);
  627. X     fprintf(stderr,"\n");
  628. X
  629. Xif (total_replies==0) {
  630. X          min_reply=0; max_reply=0; total_replies=1; sum_replies=0;
  631. X}
  632. X
  633. X     fprintf(stderr," %8d msec (min round trip time)\n",min_reply);
  634. X     fprintf(stderr," %8d msec (avg round trip time)\n",(int)sum_replies/total_replies);
  635. X     fprintf(stderr," %8d msec (max round trip time)\n",max_reply);
  636. X     fprintf(stderr," %8.3f sec (elapsed real time)\n",
  637. X         timeval_diff( &end_time,&start_time)/1000.0);
  638. X     fprintf(stderr,"\n");
  639. X
  640. X  }
  641. X
  642. X  if (num_noaddress) exit(2);
  643. X  else if (num_alive != num_hosts) exit(1); 
  644. X  
  645. X  exit(0);
  646. X
  647. X}
  648. X
  649. X
  650. X/*
  651. X * 
  652. X * Compose and transmit an ICMP_ECHO REQUEST packet.  The IP packet
  653. X * will be added on by the kernel.  The ID field is our UNIX process ID,
  654. X * and the sequence number is an index into an array of outstanding
  655. X * ping requests. The sequence number will later be used to quickly
  656. X * figure out who the ping reply came from.
  657. X *
  658. X */
  659. X
  660. X#ifdef _NO_PROTO
  661. Xvoid send_ping(s,h)
  662. Xint s; HOST_ENTRY *h;
  663. X#else
  664. Xvoid send_ping(int s,HOST_ENTRY *h)
  665. X#endif
  666. X{
  667. X  static char buffer[32];
  668. X  struct icmp *icp = (struct icmp *) buffer;
  669. X  int n,len;
  670. X
  671. X  gettimeofday(&h->last_time,&tz);
  672. X
  673. X  icp->icmp_type = ICMP_ECHO;
  674. X  icp->icmp_code = 0;
  675. X  icp->icmp_cksum = 0;
  676. X  icp->icmp_seq = h->i;
  677. X  icp->icmp_id = ident;
  678. X#define SIZE_ICMP_HDR 8
  679. X#define SIZE_PACK_SENT (sizeof(h->num_packets_sent))
  680. X#define SIZE_LAST_TIME (sizeof(h->last_time))
  681. X
  682. X  bcopy(&h->last_time,&buffer[SIZE_ICMP_HDR],SIZE_LAST_TIME);
  683. X  bcopy(&h->num_packets_sent,
  684. X             &buffer[SIZE_ICMP_HDR+SIZE_LAST_TIME], SIZE_PACK_SENT);
  685. X
  686. X  len = SIZE_ICMP_HDR+SIZE_LAST_TIME+SIZE_PACK_SENT;
  687. X
  688. X  icp->icmp_cksum = in_cksum( (u_short *)icp, len );
  689. X
  690. X  n = sendto( s, buffer, len, 0, (struct sockaddr *)&h->saddr, 
  691. X                                               sizeof(struct sockaddr_in) );
  692. X  if( n < 0 || n != len ) {
  693. X      if (verbose_flag || unreachable_flag) {
  694. X        if (dns_flag) printf("%s",get_host_by_address(h->saddr.sin_addr));
  695. X         else printf("%s",cursor->host);
  696. X         if (verbose_flag) printf(" error while sending ping: %s\n",
  697. X                               sys_errlist[errno]);
  698. X         printf("\n");
  699. X      }
  700. X      num_unreachable++;
  701. X      remove_job(h); 
  702. X  } else {
  703. X       h->num_packets_sent++;
  704. X       num_pingsent++;
  705. X  }
  706. X
  707. X}
  708. X
  709. X#ifdef _NO_PROTO
  710. Xint wait_for_reply()
  711. X#else
  712. Xint wait_for_reply()
  713. X#endif
  714. X{
  715. Xint result;
  716. Xstatic char buffer[4096];
  717. Xstruct sockaddr_in response_addr;
  718. Xstruct ip *ip;
  719. Xint hlen;
  720. Xstruct icmp *icp;
  721. Xint n;
  722. XHOST_ENTRY *h;
  723. X
  724. Xlong this_reply;
  725. Xint the_index;
  726. Xstruct timeval sent_time;
  727. X
  728. X
  729. X result=recvfrom_wto(s,buffer,4096,
  730. X                     (struct sockaddr *)&response_addr,interval);
  731. X
  732. X  if (result<0) { return 0; } /* timeout */
  733. X  
  734. X  ip = (struct ip *) buffer;
  735. X  hlen = ip->ip_hl << 2;
  736. X  if (result < hlen+ICMP_MINLEN) { return(1); /* too short */ }
  737. X
  738. X  icp = (struct icmp *)(buffer + hlen);
  739. X
  740. X  if ( 
  741. X       ( icp->icmp_type != ICMP_ECHOREPLY ) ||   
  742. X       ( icp->icmp_id   != ident          ) 
  743. X  ) {
  744. X       return 1; /* packet received, but not the one we are looking for! */
  745. X  }
  746. X
  747. X      num_pingreceived++;
  748. X
  749. X  if ( ( icp->icmp_seq  >= num_hosts    ) ||
  750. X       ( !table[icp->icmp_seq]          ) ||
  751. X       ( table[icp->icmp_seq]->saddr.sin_addr.s_addr 
  752. X                                != response_addr.sin_addr.s_addr)) { 
  753. X       return 1; /* packet received, don't about it anymore */
  754. X  }
  755. X
  756. X    n=icp->icmp_seq;
  757. X    h=table[n];
  758. X
  759. X    gettimeofday(¤t_time,&tz);
  760. X    bcopy(&icp->icmp_data[0],&sent_time,sizeof(sent_time));
  761. X    bcopy(&icp->icmp_data[SIZE_LAST_TIME],&the_index,  sizeof(the_index));
  762. X    this_reply = timeval_diff(¤t_time,&sent_time);
  763. X    if (this_reply>max_reply) max_reply=this_reply;
  764. X    if (this_reply<min_reply) min_reply=this_reply;
  765. X    sum_replies += this_reply;
  766. X    total_replies++;
  767. X
  768. X    if(verbose_flag||alive_flag) {
  769. X       if (dns_flag) printf("%s",get_host_by_address(response_addr.sin_addr));
  770. X       else printf("%s",h->host);
  771. X       if (verbose_flag) printf(" is alive");
  772. X       if (elapsed_flag) printf(" (%d msec)",this_reply);
  773. X       printf("\n");
  774. X    }
  775. X    num_alive++;
  776. X    remove_job(h); /* remove job */
  777. X    return num_waiting;
  778. X}
  779. X
  780. X/*
  781. X * Checksum routine for Internet Protocol family headers (C Version)
  782. X * From ping examples in W.Richard Stevens "UNIX NETWORK PROGRAMMING" book.
  783. X */
  784. X
  785. X#ifdef _NO_PROTO
  786. Xint in_cksum(p,n)
  787. Xu_short *p; int n;
  788. X#else
  789. Xint in_cksum(u_short *p, int n)
  790. X#endif
  791. X{
  792. X  register u_short answer;
  793. X  register long sum = 0;
  794. X  u_short odd_byte = 0;
  795. X
  796. X  while( n > 1 )  { sum += *p++; n -= 2; }
  797. X
  798. X  /* mop up an odd byte, if necessary */
  799. X  if( n == 1 ) {
  800. X      *(u_char *)(&odd_byte) = *(u_char *)p;
  801. X      sum += odd_byte;
  802. X  }
  803. X
  804. X  sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  805. X  sum += (sum >> 16);            /* add carry */
  806. X  answer = ~sum;            /* ones-complement, truncate*/
  807. X  return (answer);
  808. X}
  809. X
  810. X
  811. X/* add host to linked list of hosts to be pinged */
  812. X/* assume memory for *host is ours!!!            */
  813. X
  814. X#ifdef _NO_PROTO
  815. Xvoid add_host(host)
  816. Xchar *host;
  817. X#else
  818. Xvoid add_host(char *host)
  819. X#endif
  820. X{
  821. X  HOST_ENTRY *p;
  822. X  struct hostent *host_ent;
  823. X  struct in_addr *host_add;
  824. X
  825. X  u_long ipaddress = inet_addr(host);
  826. X
  827. X  if ( (ipaddress == -1) &&
  828. X       ( ((host_ent=gethostbyname(host)) == 0) ||
  829. X          ((host_add = (struct in_addr *) *(host_ent->h_addr_list))==0))
  830. X     )  {
  831. X          if (verbose_flag) fprintf(stderr,"%s address not found\n",host);
  832. X          num_noaddress++;
  833. X          return;
  834. X       }
  835. X
  836. X  p = (HOST_ENTRY *) malloc(sizeof(HOST_ENTRY));
  837. X  if (!p) crash_and_burn("can't allocate HOST_ENTRY");
  838. X
  839. X  p->host=host;
  840. X  p->num_packets_sent = 0;
  841. X  p->last_time.tv_sec =0;
  842. X  p->last_time.tv_usec =0;
  843. X
  844. X  bzero((char*) &p->saddr, sizeof(p->saddr));
  845. X  p->saddr.sin_family      = AF_INET;
  846. X
  847. X  if (ipaddress==-1) p->saddr.sin_addr = *host_add; 
  848. X  else p->saddr.sin_addr.s_addr = ipaddress;
  849. X
  850. X  if (!rrlist) {
  851. X      rrlist = p;
  852. X      p->next = p;
  853. X      p->prev = p;
  854. X  } else {
  855. X      p->next = rrlist;
  856. X      p->prev = rrlist->prev;
  857. X      p->prev->next = p;
  858. X      p->next->prev = p;
  859. X      rrlist = p;
  860. X  }
  861. X  num_hosts++;
  862. X}
  863. X
  864. X#ifdef _NO_PROTO
  865. Xvoid remove_job(h)
  866. XHOST_ENTRY *h;
  867. X#else
  868. Xvoid remove_job(HOST_ENTRY *h)
  869. X#endif
  870. X{
  871. X
  872. X  table[h->i]=NULL;
  873. X  --num_waiting;
  874. X
  875. X  if (num_waiting) {                    /* remove us from list of jobs */
  876. X       h->prev->next = h->next;
  877. X       h->next->prev = h->prev;
  878. X       if (h==cursor) { cursor = h-> next; }
  879. X  } else {     
  880. X       cursor=NULL;
  881. X       rrlist=NULL;
  882. X  }
  883. X
  884. X}
  885. X
  886. X#ifdef _NO_PROTO
  887. Xchar *get_host_by_address(in)
  888. Xstruct in_addr in;
  889. X#else
  890. Xchar *get_host_by_address(struct in_addr in)
  891. X#endif
  892. X{
  893. X  struct hostent *h;
  894. X   h=gethostbyaddr((char *) &in,sizeof(struct in_addr),AF_INET);
  895. X   if (h==NULL || h->h_name==NULL) return inet_ntoa(in);
  896. X   else return h->h_name;
  897. X}
  898. X
  899. X
  900. X#ifdef _NO_PROTO
  901. Xvoid crash_and_burn(message)
  902. Xchar *message;
  903. X#else
  904. Xvoid crash_and_burn(char *message)
  905. X#endif
  906. X{
  907. X  if (verbose_flag) fprintf(stderr,"%s: %s\n",prog,message);
  908. X  exit(4);
  909. X}
  910. X
  911. X#ifdef _NO_PROTO
  912. Xvoid errno_crash_and_burn(message)
  913. Xchar *message;
  914. X#else
  915. Xvoid errno_crash_and_burn(char *message)
  916. X#endif
  917. X{
  918. X  if (verbose_flag)
  919. X        fprintf(stderr,"%s: %s : %s\n",prog,message,sys_errlist[errno]);
  920. X  exit(4);
  921. X}
  922. X
  923. X#ifdef _NO_PROTO
  924. Xlong timeval_diff(a,b)
  925. Xstruct timeval *a,*b;
  926. X#else
  927. Xlong timeval_diff(struct timeval *a,struct timeval *b)
  928. X#endif
  929. X{
  930. Xdouble temp;
  931. X
  932. Xtemp = 
  933. X  (((a->tv_sec*1000000)+ a->tv_usec) - 
  934. X     ((b->tv_sec*1000000)+ b->tv_usec))/1000;
  935. X
  936. Xreturn (long) temp;
  937. X
  938. X}
  939. X
  940. X/*
  941. X * recvfrom_wto: receive with timeout
  942. X *      returns length of data read or -1 if timeout
  943. X *      crash_and_burn on any other errrors
  944. X *
  945. X */
  946. X
  947. X
  948. X#ifdef _NO_PROTO
  949. Xint recvfrom_wto (s,buf,len, saddr, timo)
  950. Xint s; char *buf; int len; struct sockaddr *saddr; int timo;
  951. X#else
  952. Xint recvfrom_wto (int s, char *buf, int len, struct sockaddr *saddr, int timo)
  953. X#endif
  954. X{
  955. X  int nfound,slen,n;
  956. X  struct timeval to;
  957. X  fd_set readset,writeset;
  958. X
  959. X  to.tv_sec  = timo/1000;
  960. X  to.tv_usec = (timo - (to.tv_sec*1000))*1000;
  961. X
  962. X  FD_ZERO(&readset);
  963. X  FD_ZERO(&writeset);
  964. X  FD_SET(s,&readset);
  965. X  nfound = select(s+1,&readset,&writeset,NULL,&to);
  966. X  if (nfound<0) errno_crash_and_burn("select");
  967. X  if (nfound==0) return -1;  /* timeout */
  968. X  slen=sizeof(struct sockaddr);
  969. X  n=recvfrom(s,buf,len,0,saddr,&slen);
  970. X  if (n<0) errno_crash_and_burn("recvfrom");
  971. X  return n;
  972. X}
  973. X
  974. X#ifdef _NO_PROTO
  975. Xvoid usage()
  976. X#else
  977. Xvoid usage()
  978. X#endif
  979. X{
  980. X  fprintf(stderr,"\n");
  981. X  fprintf(stderr,"Usage: %s [options] [systems...]\n",prog);
  982. X  fprintf(stderr,"   -a         show systems that are alive\n");
  983. X  fprintf(stderr,"   -d         use dns to lookup address for return ping packet\n");
  984. X  fprintf(stderr,"   -e         show elapsed time on return packets\n");
  985. X  fprintf(stderr,"   -f file    read list of systems from a file ( - means stdin)\n");
  986. X  fprintf(stderr,"   -i n       interval (between ping packets) in milliseconds (default %d)\n",interval);
  987. X  fprintf(stderr,"   -q         quiet (don't show per host results)\n");
  988. X  fprintf(stderr,"   -r n       retry limit (default %d)\n",retry);
  989. X  fprintf(stderr,"   -s         dump final stats\n");
  990. X  fprintf(stderr,"   -t n       individual host timeout in milliseconds (default %d)\n",timeout);
  991. X  fprintf(stderr,"   -u         show systems that are unreachable\n");
  992. X  fprintf(stderr,"   -v         show version\n");
  993. X  fprintf(stderr,"   systems    list of systems to check (if no -f specified)\n");
  994. X  fprintf(stderr,"\n");
  995. X  exit(3);
  996. X}
  997. END_OF_FILE
  998. if test 23070 -ne `wc -c <'fping.c'`; then
  999.     echo shar: \"'fping.c'\" unpacked with wrong size!
  1000. fi
  1001. # end of 'fping.c'
  1002. fi
  1003. if test -f 'fping.man' -a "${1}" != "-c" ; then 
  1004.   echo shar: Will not clobber existing file \"'fping.man'\"
  1005. else
  1006. echo shar: Extracting \"'fping.man'\" \(3896 characters\)
  1007. sed "s/^X//" >'fping.man' <<'END_OF_FILE'
  1008. X.TH fping l
  1009. X.SH NAME
  1010. Xfping \- send ICMP ECHO_REQUEST packets to network hosts
  1011. X.SH SYNOPSIS
  1012. X.B fping
  1013. X[ \fIoptions\fR ]
  1014. X[ \fIsystems...\fR ]
  1015. X
  1016. X.SH DESCRIPTION
  1017. X.NXR "fping command"
  1018. X.NXR "ICMP ECHO_REQUEST"
  1019. X
  1020. X      
  1021. X.B fping 
  1022. Xis a 
  1023. X.MS ping 8
  1024. Xlike program which uses the Internet Control
  1025. XMessage Protocol (ICMP) echo request to determine if a host is
  1026. Xup. 
  1027. X.B fping 
  1028. Xis different from ping in that you can specify any
  1029. Xnumber of hosts on the command line, or specify a file containing
  1030. Xthe lists of hosts to ping. Instead of trying one host until it
  1031. Xtimeouts or replies, 
  1032. X.B fping 
  1033. Xwill send out a ping packet and move
  1034. Xon to the next host in a round-robin fashion. If a host replies,
  1035. Xit is noted and removed from the list of hosts to check. If a host
  1036. Xdoes not respond within a certain time limit and/or retry limit it 
  1037. Xwill be considered unreachable. 
  1038. X.PP
  1039. XUnlike 
  1040. X.MS ping 8
  1041. X,
  1042. X.B fping 
  1043. Xis meant to be used in scripts and its output is easy to parse.
  1044. X.SH OPTIONS
  1045. X.IP \fB-a\fR 5
  1046. XShow systems that are alive.
  1047. X.IP \fB-d\fR 5
  1048. XUse DNS to lookup address of return ping packet. This allows you to give
  1049. Xfping a list of IP addresses as input and print hostnames in the output.
  1050. X.IP \fB-e\fR 5
  1051. XShow elapsed (round-trip) time of packets
  1052. X.IP \fB-f\fR 5
  1053. XRead list of system from a file.
  1054. X.IP \fB-i\fIn\fR 5
  1055. XThe minimum amount of time (in milliseconds) between sending a ping packet to any host (default is 25).
  1056. X.IP \fB-q\fR 5
  1057. XQuiet. Don't show per host results, just set final exit status.
  1058. X.IP \fB-r\fIn\fR 5
  1059. XRetry limit (default 3). This is the number of times an attempt at pinging
  1060. Xa host will be made, not including the first try.
  1061. X.IP \fB-s\fR 5
  1062. XDump final statistics.
  1063. X.IP \fB-t\fIn\fR 5
  1064. XIndividual host timeout in milliseconds (default 2500). This is the 
  1065. Xminimum number of milliseconds between ping packets directed towards a given
  1066. Xhost.
  1067. X.IP \fB-u\fR 5
  1068. XShow systems that are unreachable.
  1069. X.B fping
  1070. Xa list of IP addresses as input and have the results printed as hostnames.
  1071. X.SH EXAMPLES
  1072. XThe following perl script will check a list of hosts and send mail if
  1073. Xany are unreachable. It uses the open2 function which allows a program
  1074. Xto be opened for reading and writing. fping does not start pinging the
  1075. Xlist of systems until it reads EOF, which it gets after INPUT is closed. 
  1076. XSure the open2 usage is not need in this example, but its a good open2
  1077. Xexample none the less. 
  1078. X.nf
  1079. X
  1080. X#!/usr/local/bin/perl
  1081. Xrequire 'open2.pl';
  1082. X
  1083. X$MAILTO = "root";
  1084. X
  1085. X$pid = &open2("OUTPUT","INPUT","/usr/local/bin/fping -u");
  1086. X
  1087. X@check=("slapshot","foo","foobar");
  1088. X
  1089. Xforeach(@check) {  print INPUT "$_\\n"; }
  1090. Xclose(INPUT);
  1091. X@output=<OUTPUT>;
  1092. X
  1093. Xif ($#output != -1) {
  1094. X chop($date=`date`);
  1095. X open(MAIL,"|mail -s 'unreachable systems' $MAILTO");
  1096. X print MAIL "\\nThe following systems are unreachable as of: $date\\n\\n";
  1097. X print MAIL @output;
  1098. X close MAIL;
  1099. X}
  1100. X
  1101. X.ni
  1102. XAnother good example is when you want to perform an action only on hosts
  1103. Xthat are currently reachable.
  1104. X.nf
  1105. X
  1106. X#!/usr/local/bin/perl
  1107. X
  1108. X$hosts_to_backup = `cat /etc/hosts.backup | fping -a`;
  1109. X
  1110. Xforeach $host (split(/\\n/,$hosts_to_backup)) {
  1111. X  # do it
  1112. X}
  1113. X
  1114. X.ni
  1115. X
  1116. X.SH AUTHOR
  1117. XRoland J. Schemers III, Stanford University
  1118. X.SH DIAGNOSTICS
  1119. XExit status is 0 if all the hosts are reachable, 1 if some hosts were
  1120. Xunreachable, 2 if any IP addresses were not found, 3 for invalid
  1121. Xcommand line arguments, and 4 for a system call failure.
  1122. X.SH BUGS
  1123. XHa! If there were any I knew of I would have fixed them!
  1124. X.SH RESTRICTIONS
  1125. XIf certain options are used (i.e, a low value for -i and -t, and a 
  1126. Xhigh value for -r) it is possible to flood the network. This program
  1127. Xmust be installed as setuid root in order to open up a raw socket,
  1128. Xor must be run by root. In order to stop mere mortals from hosing the
  1129. Xnetwork (when fping is installed setuid root) , normal users can't specify 
  1130. Xthe following:
  1131. X.nf
  1132. X
  1133. X -i n   where n < 10  msec
  1134. X -r n   where n > 20
  1135. X -t n   where n < 250 msec
  1136. X
  1137. X.ni
  1138. X.SH SEE ALSO
  1139. Xnetstat(1), ping(8), ifconfig(8c)
  1140. X
  1141. END_OF_FILE
  1142. if test 3896 -ne `wc -c <'fping.man'`; then
  1143.     echo shar: \"'fping.man'\" unpacked with wrong size!
  1144. fi
  1145. # end of 'fping.man'
  1146. fi
  1147. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1148.   echo shar: Will not clobber existing file \"'Makefile'\"
  1149. else
  1150. echo shar: Extracting \"'Makefile'\" \(1077 characters\)
  1151. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1152. X
  1153. XPROG= fping
  1154. XOBJS= fping.o
  1155. XSRC= fping.c
  1156. XBIN= /usr/local/bin
  1157. XMAN= /usr/man/manl
  1158. XMANSRC= fping.man
  1159. XMANDST= fping.l
  1160. X
  1161. X#
  1162. X# Interval is the minimum amount of time between sending a ping packet to 
  1163. X# any host.
  1164. X#
  1165. X# Timeout  is the minimum amount of time between sending a ping packet to
  1166. X# a particular host.
  1167. X#
  1168. X# Retry is the number of ping packets to send to a host before giving up.
  1169. X#
  1170. X
  1171. XDEFAULTS= -DDEFAULT_INTERVAL=25  \
  1172. X          -DDEFAULT_TIMEOUT=2500  \
  1173. X          -DDEFAULT_RETRY=3
  1174. X#
  1175. X# some systems need the following:
  1176. X#
  1177. X#LIBS= -lsocket
  1178. X
  1179. XLIBS=
  1180. X
  1181. Xall: $(PROG)
  1182. X
  1183. X$(PROG) : $(OBJS)
  1184. X    $(CC) $(OBJS) -o $(PROG) $(LIBS)
  1185. X
  1186. X$(OBJS) : $(SRC)
  1187. X    $(CC) $(CFLAGS) -c $(DEFAULTS) $(SRC)
  1188. X
  1189. X# if you don't have install type:
  1190. X# cp $(PROG) /usr/local/bin
  1191. X# chown root /usr/local/bin/$(PROG)
  1192. X# chmod 4555 /usr/local/bin/$(PROG)
  1193. X# strip      /usr/local/bin/$(PROG)
  1194. X#
  1195. X
  1196. Xinstall:
  1197. X    install -c -m 4555 -o root -s $(PROG) $(BIN)/$(PROG)
  1198. X    install -c -m 0444 -o root $(MANSRC) $(MAN)/$(MANDST)
  1199. X
  1200. Xclean:
  1201. X    rm -f a.out core *~  *.o $(PROG)
  1202. X
  1203. Xshar:
  1204. X    shar README CHANGES fping.c fping.man Makefile README.VMS > fping.shar
  1205. END_OF_FILE
  1206. if test 1077 -ne `wc -c <'Makefile'`; then
  1207.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1208. fi
  1209. # end of 'Makefile'
  1210. fi
  1211. if test -f 'README.VMS' -a "${1}" != "-c" ; then 
  1212.   echo shar: Will not clobber existing file \"'README.VMS'\"
  1213. else
  1214. echo shar: Extracting \"'README.VMS'\" \(5510 characters\)
  1215. sed "s/^X//" >'README.VMS' <<'END_OF_FILE'
  1216. XFrom <@jessica.stanford.edu:IVERSEN@VSFYS1.FI.UIB.NO> Mon Jul 27 08:54:26 1992
  1217. XReceived: from Argus.Stanford.EDU by jessica.stanford.edu (5.59/25-eef) id AA28695; Mon, 27 Jul 92 08:54:22 PDT
  1218. XReceived: from vsfys1.fi.uib.no by Argus.Stanford.EDU (5.65/inc-1.0)
  1219. X    id AA28942; Mon, 27 Jul 92 08:54:19 -0700
  1220. XDate:    Mon, 27 Jul 1992 17:54:17 +0200
  1221. XFrom: IVERSEN@VSFYS1.FI.UIB.NO (Per Steinar Iversen, Dept. of Physics, Univ. of Bergen, Norway, phone +47-5-212770)
  1222. XMessage-Id: <920727175417.21e004ce@VSFYS1.FI.UIB.NO>
  1223. XSubject: FPING under VMS
  1224. XTo: schemers@Stanford.EDU
  1225. XX-Vmsmail-To: SMTP%"schemers@Stanford.EDU"
  1226. XStatus: OR
  1227. X
  1228. XHello,
  1229. X
  1230. XI rather liked your recently posted fping, and I decided to port it to VMS,
  1231. Xunder MultiNet TCP/IP 3.0H and VAXC 3.2. Only some very minor modifications are
  1232. Xnecessary to run it under VMS 5.5: 
  1233. X
  1234. X1) The 2 following lines must be put onto one single line, otherwise VAXC 
  1235. Xcomplains:
  1236. X
  1237. X#if !__STDC__ && !defined(__cplusplus) && !defined(FUNCPROTO) \
  1238. X                                                 && !defined(_POSIX_SOURCE)
  1239. X
  1240. Xgoes to:
  1241. X
  1242. X#if !__STDC__ && !defined(__cplusplus) && !defined(FUNCPROTO) && !defined(_POSIX_SOURCE)
  1243. X
  1244. X2) The single following line must be changed:
  1245. X
  1246. Xextern char *sys_errlist[];
  1247. X
  1248. Xto:
  1249. X
  1250. X#ifndef VMS
  1251. Xextern char *sys_errlist[];
  1252. X#else
  1253. Xextern noshare char *sys_errlist[];
  1254. X#endif
  1255. X
  1256. X3) VMS runs privileged programs in a different manner from UNIX. geteuid is 
  1257. X"supported" by VAXC but the result is not really meaningful.
  1258. X
  1259. XThese lines are thus Unix specific:
  1260. X
  1261. X  /* check if we are root */
  1262. X
  1263. X#ifndef VMS
  1264. X  if (geteuid()) {
  1265. X      fprintf(stderr,
  1266. X        "This program can only be run by root, or it must be setuid root.\n");
  1267. X      exit(3);
  1268. X  }
  1269. X#endif
  1270. X
  1271. X4) VAXC does not support getopt. I got my copies of getopt, index and rindex
  1272. Xfrom a fileserver with bsd-sources, using anonymous FTP. These routines
  1273. Xcompiled without complaints and works fine under VAXC 3.2 at least. 
  1274. X
  1275. X5) The VMS concept of exit codes is different from the Unix version. After some
  1276. Xthought I decided to short circuit the VAXC attempt of translating the Unix
  1277. Xreturn codes into VMS style return codes. My version of FPING always returns
  1278. X"exit(1)", which is VMS success. However the FPING status codes are put into a
  1279. XVMS symbol, FPING_STATUS. It is thus very easy to use the FPING return status
  1280. Xcodes for further action if needed. 
  1281. X
  1282. XThe line at the end of main in FPING, "return 0;", must be changed to
  1283. X"exit(0);" for VMS, this should be OK for Unix too?
  1284. X
  1285. XA small routine is needed to handle the translation, it will probably not
  1286. Xget any rewards for nice C-code (I usually program in Fortran), and it was 
  1287. Xlargely created by copying an example from the VAXC manuals:
  1288. X
  1289. X/* VMS-EXIT.C */
  1290. X#include <ssdef>
  1291. X#include <stdio>
  1292. X#include <descrip>
  1293. X
  1294. Xint LIB$SET_SYMBOL();
  1295. X
  1296. Xvms_exit (ecode)
  1297. Xint ecode;
  1298. X{
  1299. X  int status = 1;
  1300. X  static $DESCRIPTOR(fping_name, "FPING_STATUS");
  1301. X  static $DESCRIPTOR(fping_exit_0,"0");
  1302. X  static $DESCRIPTOR(fping_exit_1,"1");
  1303. X  static $DESCRIPTOR(fping_exit_2,"2");
  1304. X  static $DESCRIPTOR(fping_exit_3,"3");
  1305. X  static $DESCRIPTOR(fping_exit_4,"4");
  1306. X  static $DESCRIPTOR(fping_exit_5,"5");
  1307. X
  1308. X  switch(ecode) {
  1309. X  case 0 :
  1310. X    status = LIB$SET_SYMBOL(&fping_name,&fping_exit_0);
  1311. X    break;
  1312. X  case 1 :
  1313. X    status = LIB$SET_SYMBOL(&fping_name,&fping_exit_1);
  1314. X    break;
  1315. X  case 2 :
  1316. X    status = LIB$SET_SYMBOL(&fping_name,&fping_exit_2);
  1317. X    break;
  1318. X  case 3 :
  1319. X    status = LIB$SET_SYMBOL(&fping_name,&fping_exit_3);
  1320. X    break;
  1321. X  case 4 :
  1322. X    status = LIB$SET_SYMBOL(&fping_name,&fping_exit_4);
  1323. X    break;
  1324. X  default:
  1325. X    status = LIB$SET_SYMBOL(&fping_name,&fping_exit_5);
  1326. X    break;
  1327. X  }
  1328. X
  1329. X  exit(1);
  1330. X
  1331. X}
  1332. X
  1333. X
  1334. X6) The following command file (script) was used to compile and link under VMS:
  1335. X
  1336. X$! VMS-CC-MAKE.COM
  1337. X$! 
  1338. X$! This compile+link procedure has been tested with VAXC 3.2 and
  1339. X$! MultiNet 3.0H.
  1340. X$!
  1341. X$! NOTE: getopt, index, and rindex are not part of VAXC, however the BSD
  1342. X$! versions works fine. They should be available by anonymous FTP
  1343. X$! from a number of fileservers.
  1344. X$!
  1345. X$ define/user arpa             multinet_root:[multinet.include.arpa]
  1346. X$ define/user netinet          multinet_root:[multinet.include.netinet]
  1347. X$ define/user sys              multinet_root:[multinet.include.sys],sys$library
  1348. X$ cc /nolist /define="exit=vms_exit" fping.c
  1349. X$ cc /nolist                         vms-exit.c
  1350. X$ cc /nolist                         getopt.c
  1351. X$ cc /nolist                         index.c
  1352. X$ cc /nolist                         rindex.c
  1353. X$ link /nomap/notrace fping,vms-exit,getopt,index,rindex,sys$input/opt
  1354. Xmultinet:multinet_socket_library/share
  1355. Xsys$share:vaxcrtl/share
  1356. X$ delete fping.obj.*,vms-exit.obj.*,getopt.obj.*,index.obj.*,rindex.obj.*
  1357. X$ purge  fping.exe
  1358. X$ fping :== $'f$environment("default")'fping
  1359. X
  1360. X7) Piping files into fping is not available under VMS, but the "f" option does
  1361. Xthe same job.
  1362. X
  1363. X8) fping must be installed with privileges if it is to be used by
  1364. Xnon-privileged users under VMS. 
  1365. X
  1366. XThe question then is, does it work? Well, as far I can see the answer is yes!
  1367. XHere are some examples of output:
  1368. X
  1369. X$ fping xxx
  1370. Xxxx address not found
  1371. X$ show symbol fping_status
  1372. X  FPING_STATUS = "2"
  1373. X$ fping vxcrna.cern.ch
  1374. Xvxcrna.cern.ch is alive
  1375. X$ show symbol fping_status
  1376. X  FPING_STATUS = "0"
  1377. X$ fping -de vxcrna.cern.ch
  1378. Xvxcrna.cern.ch is alive (320 msec)
  1379. X$ show symbol fping_status
  1380. X  FPING_STATUS = "0"
  1381. X$ fping -v
  1382. Xvsfys5$dkb100:[scratch.iversen]fping.exe;7: $Revision: 1.17 $ $Date: 1992/07/23 03:29:42 $
  1383. Xvsfys5$dkb100:[scratch.iversen]fping.exe;7: comments to schemers@Stanford.EDU
  1384. X
  1385. XRegards, Per (iversen@vsfys1.fi.uib.no)
  1386. X
  1387. END_OF_FILE
  1388. if test 5510 -ne `wc -c <'README.VMS'`; then
  1389.     echo shar: \"'README.VMS'\" unpacked with wrong size!
  1390. fi
  1391. # end of 'README.VMS'
  1392. fi
  1393. echo shar: End of shell archive.
  1394. exit 0
  1395.