1 /* sonar.c --- Simulate a sonar screen.
3 * This is an implementation of a general purpose reporting tool in the
4 * format of a Sonar display. It is designed such that a sensor is read
5 * on every movement of a sweep arm and the results of that sensor are
6 * displayed on the screen. The location of the display points (targets) on the
7 * screen are determined by the current localtion of the sweep and a distance
8 * value associated with the target.
10 * Currently the only two sensors that are implemented are the simulator
11 * (the default) and the ping sensor. The simulator randomly creates a set
12 * of bogies that move around on the scope while the ping sensor can be
13 * used to display hosts on your network.
15 * The ping code is only compiled in if you define HAVE_ICMP or HAVE_ICMPHDR,
16 * because, unfortunately, different systems have different ways of creating
17 * these sorts of packets.
19 * Also: creating an ICMP socket is a privileged operation, so the program
20 * needs to be installed SUID root if you want to use the ping mode. If you
21 * check the code you will see that this privilige is given up immediately
22 * after the socket is created.
24 * It should be easy to extend this code to support other sorts of sensors.
26 * - search the output of "netstat" for the list of hosts to ping;
27 * - plot the contents of /proc/interrupts;
28 * - plot the process table, by process size, cpu usage, or total time;
29 * - plot the logged on users by idle time or cpu usage.
31 * Copyright (C) 1998, 2001
32 * by Stephen Martin (smartin@vanderfleet-martin.net).
33 * Permission to use, copy, modify, distribute, and sell this software and its
34 * documentation for any purpose is hereby granted without fee, provided that
35 * the above copyright notice appear in all copies and that both that
36 * copyright notice and this permission notice appear in supporting
37 * documentation. No representations are made about the suitability of this
38 * software for any purpose. It is provided "as is" without express or
43 * Version 1.0 April 27, 1998.
45 * - Submitted to RedHat Screensaver Contest
47 * Version 1.1 November 3, 1998.
48 * - Added simulation mode.
49 * - Added enhancements by Thomas Bahls <thommy@cs.tu-berlin.de>
50 * - Fixed huge memory leak.
51 * - Submitted to xscreensavers
54 * - All ping code is now ifdef-ed by the compile time symbol HAVE_PING;
55 * use -DHAVE_PING to include it when you compile.
56 * - Sweep now uses gradients.
57 * - Fixed portability problems with icmphdr on some systems.
58 * - removed lowColor option/resource.
59 * - changed copyright notice so that it could be included in the xscreensavers
62 * Version 1.3 November 16, 1998.
63 * - All ping code is now ifdef-ed by the compile time symbol PING use -DPING
64 * to include it when you compile.
65 * - Sweep now uses gradients.
66 * - Fixed portability problems with icmphdr on some systems.
67 * - removed lowcolour option/resource.
68 * - changed copyright notice so that it could be included in the xscreensavers
71 * Version 1.4 November 18, 1998.
72 * - More ping portability fixes.
74 * Version 1.5 November 19, 1998.
75 * - Synced up with jwz's changes.
76 * - Now need to define HAVE_PING to compile in the ping stuff.
79 /* These are computed by configure now:
92 #include "screenhack.h"
96 #if defined(HAVE_ICMP) || defined(HAVE_ICMPHDR)
101 # include <sys/types.h>
102 # include <sys/time.h>
103 # include <sys/ipc.h>
104 # include <sys/shm.h>
105 # include <sys/socket.h>
106 # include <netinet/in_systm.h>
107 # include <netinet/in.h>
108 # include <netinet/ip.h>
109 # include <netinet/ip_icmp.h>
110 # include <netinet/udp.h>
111 # include <arpa/inet.h>
113 #endif /* HAVE_ICMP || HAVE_ICMPHDR */
119 #define MY_MIN(a,b) ((a)<(b)?(a - 50):(b - 10))
122 # define LINE_MAX 2048
127 #if defined(HAVE_ICMP)
130 # define ICMP_TYPE(p) (p)->icmp_type
131 # define ICMP_CODE(p) (p)->icmp_code
132 # define ICMP_CHECKSUM(p) (p)->icmp_cksum
133 # define ICMP_ID(p) (p)->icmp_id
134 # define ICMP_SEQ(p) (p)->icmp_seq
135 #elif defined(HAVE_ICMPHDR)
137 # define ICMP icmphdr
138 # define ICMP_TYPE(p) (p)->type
139 # define ICMP_CODE(p) (p)->code
140 # define ICMP_CHECKSUM(p) (p)->checksum
141 # define ICMP_ID(p) (p)->un.echo.id
142 # define ICMP_SEQ(p) (p)->un.echo.sequence
149 # if defined(__DECC) || defined(_IP_VHL)
150 /* This is how you do it on DEC C, and possibly some BSD systems. */
151 # define IP_HDRLEN(ip) ((ip)->ip_vhl & 0x0F)
153 /* This is how you do it on everything else. */
154 # define IP_HDRLEN(ip) ((ip)->ip_hl)
156 #endif /* HAVE_PING */
159 /* Forward References */
162 static u_short checksum(u_short *, int);
164 static long delta(struct timeval *, struct timeval *);
167 /* Data Structures */
172 * This represents an object that is visible on the scope.
175 typedef struct Bogie {
176 char *name; /* The name of the thing being displayed */
177 char *desc; /* Beneath the name (e.g., ping time) */
178 int distance; /* The distance to this thing (0 - 100) */
179 int tick; /* The tick that it was found on */
180 int ttl; /* The time to live */
181 int age; /* How long it's been around */
182 struct Bogie *next; /* The next one in the list */
188 * This contains all of the runtime information about the sonar scope.
192 Display *dpy; /* The X display */
193 Window win; /* The window */
194 GC hi, /* The leading edge of the sweep */
195 lo, /* The trailing part of the sweep */
196 erase, /* Used to erase things */
197 grid, /* Used to draw the grid */
198 text; /* Used to draw text */
199 Colormap cmap; /* The colormap */
200 XFontStruct *font; /* The font to use for the labels */
201 int text_steps; /* How many steps to fade text. */
202 XColor *text_colors; /* Pixel values used to fade text */
203 int sweep_degrees; /* How much of the circle the sweep uses */
204 int sweep_segs; /* How many gradients in the sweep. */
205 XColor *sweep_colors; /* The sweep pixel values */
206 int width, height; /* Window dimensions */
207 int minx, miny, maxx, maxy, /* Bounds of the scope */
208 centrex, centrey, radius; /* Parts of the scope circle */
209 Bogie *visible; /* List of visible objects */
210 int current; /* Current position of sweep */
211 int sweepnum; /* The current id of the sweep */
212 int delay; /* how long between each frame of the anim */
214 int TTL; /* The number of ticks that bogies are visible
215 on the screen before they fade away. */
218 static Bool debug_p = False;
219 static Bool resolve_p = True;
220 static Bool times_p = True;
224 * Variables to support the differnt Sonar modes.
227 Bogie *(*sensor)(sonar_info *, void *); /* The current sensor */
228 void *sensor_info; /* Information about the sensor */
231 * A list of targets to ping.
234 typedef struct ping_target {
235 char *name; /* The name of the target */
237 struct sockaddr address; /* The address of the target */
238 #endif /* HAVE_PING */
239 struct ping_target *next; /* The next one in the list */
247 * This contains the information for the ping sensor.
251 int icmpsock; /* Socket for sending pings */
252 int pid; /* Our process ID */
253 int seq; /* Packet sequence number */
254 int timeout; /* Timeout value for pings */
255 ping_target *targets; /* List of targets to ping */
256 int numtargets; /* The number of targets to ping */
259 /* Flag to indicate that the timer has expired on us */
261 static int timer_expired;
263 #endif /* HAVE_PING */
266 * A list of targets for the simulator
269 typedef struct sim_target {
270 char *name; /* The name of the target */
271 int nexttick; /* The next tick that this will be seen */
272 int nextdist; /* The distance on that tick */
273 int movedonsweep; /* The number of the sweep this last moved */
277 * Simulator Information.
279 * This contains the information for the simulator mode.
283 sim_target *teamA; /* The bogies for the A team */
284 int numA; /* The number of bogies in team A */
285 char *teamAID; /* The identifier for bogies in team A */
286 sim_target *teamB; /* The bogies for the B team */
287 int numB; /* The number of bogies in team B */
288 char *teamBID; /* The identifier for bogies in team B */
291 /* Name of the Screensaver hack */
293 char *progclass="sonar";
295 /* Application Defaults */
297 char *defaults [] = {
298 ".background: #000000",
299 ".sweepColor: #00FF00",
301 "*scopeColor: #003300",
302 "*gridColor: #00AA00",
303 "*textColor: #FFFF00",
309 "*textSteps: 80", /* npixels */
310 "*sweepSegments: 80", /* npixels */
312 "*pingTimeout: 3000",
326 /* Options passed to this program */
328 XrmOptionDescRec options [] = {
329 {"-background", ".background", XrmoptionSepArg, 0 },
330 {"-sweep-color", ".sweepColor", XrmoptionSepArg, 0 },
331 {"-scope-color", ".scopeColor", XrmoptionSepArg, 0 },
332 {"-grid-color", ".gridColor", XrmoptionSepArg, 0 },
333 {"-text-color", ".textColor", XrmoptionSepArg, 0 },
334 {"-ttl", ".ttl", XrmoptionSepArg, 0 },
335 {"-font", ".font", XrmoptionSepArg, 0 },
337 {"-ping-timeout", ".pingTimeout", XrmoptionSepArg, 0 },
338 #endif /* HAVE_PING */
339 {"-team-a-name", ".teamAName", XrmoptionSepArg, 0 },
340 {"-team-b-name", ".teamBName", XrmoptionSepArg, 0 },
341 {"-team-a-count", ".teamACount", XrmoptionSepArg, 0 },
342 {"-team-b-count", ".teamBCount", XrmoptionSepArg, 0 },
344 {"-ping", ".ping", XrmoptionSepArg, 0 },
345 {"-no-dns", ".resolve", XrmoptionNoArg, "False" },
346 {"-no-times", ".showTimes", XrmoptionNoArg, "False" },
347 {"-debug", ".debug", XrmoptionNoArg, "True" },
352 * Create a new Bogie and set some initial values.
355 * name - The name of the bogie.
356 * distance - The distance value.
357 * tick - The tick value.
358 * ttl - The time to live value.
361 * The newly allocated bogie or null if a memory problem occured.
365 newBogie(char *name, int distance, int tick, int ttl)
368 /* Local Variables */
373 /* Allocate a bogie and initialize it */
375 if ((new = (Bogie *) calloc(1, sizeof(Bogie))) == NULL) {
376 fprintf(stderr, "%s: Out of Memory\n", progname);
380 new->distance = distance;
384 new->next = (Bogie *) 0;
392 * b - The bogie to free.
399 if (b->name != (char *) 0)
405 * Find a bogie by name in a list.
407 * This does a simple linear search of the list for a given name.
410 * bl - The Bogie list to search.
411 * name - The name to look for.
414 * The requested Bogie or null if it wasn't found.
418 findNode(Bogie *bl, char *name)
421 /* Local Variables */
425 /* Abort if the list is empty or no name is given */
427 if ((name == NULL) || (bl == NULL))
430 /* Search the list for the desired name */
434 if (strcmp(p->name, name) == 0)
446 /* Packs an IP address quad into bigendian network order. */
448 pack_addr (unsigned int a, unsigned int b, unsigned int c, unsigned int d)
450 unsigned long i = (((a & 255) << 24) |
457 /* Unpacks an IP address quad from bigendian network order. */
459 unpack_addr (unsigned long addr,
460 unsigned int *a, unsigned int *b,
461 unsigned int *c, unsigned int *d)
464 *a = (addr >> 24) & 255;
465 *b = (addr >> 16) & 255;
466 *c = (addr >> 8) & 255;
472 * Lookup the address for a ping target;
475 * target - The ping_target fill in the address for.
478 * 1 if the host was successfully resolved, 0 otherwise.
482 lookupHost(ping_target *target)
484 struct hostent *hent;
485 struct sockaddr_in *iaddr;
490 iaddr = (struct sockaddr_in *) &(target->address);
491 iaddr->sin_family = AF_INET;
493 if (4 == sscanf (target->name, " %u.%u.%u.%u %c",
494 &ip[0], &ip[1], &ip[2], &ip[3], &c))
496 /* It's an IP address.
501 fprintf (stderr, "%s: ignoring bogus IP %s\n",
502 progname, target->name);
506 iaddr->sin_addr.s_addr = pack_addr (ip[0], ip[1], ip[2], ip[3]);
508 hent = gethostbyaddr ((const char *) &iaddr->sin_addr.s_addr,
509 sizeof(iaddr->sin_addr.s_addr),
515 fprintf (stderr, "%s: %s => %s\n",
516 progname, target->name,
517 ((hent && hent->h_name && *hent->h_name)
518 ? hent->h_name : "<unknown>"));
520 if (hent && hent->h_name && *hent->h_name)
521 target->name = strdup (hent->h_name);
529 /* don't waste time being confused by non-hostname tokens
530 in .ssh/known_hosts */
531 if (!strcmp (target->name, "ssh-rsa") ||
532 !strcmp (target->name, "ssh-dsa") ||
533 !strcmp (target->name, "ssh-dss") ||
534 strlen (target->name) >= 80)
537 hent = gethostbyname (target->name);
540 fprintf (stderr, "%s: could not resolve host: %s\n",
541 progname, target->name);
545 memcpy (&iaddr->sin_addr, hent->h_addr_list[0],
546 sizeof(iaddr->sin_addr));
550 unsigned int a, b, c, d;
551 unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
552 fprintf (stderr, "%s: %s => %d.%d.%d.%d\n",
553 progname, target->name, a, b, c, d);
561 print_host (FILE *out, unsigned long ip, const char *name)
564 unsigned int a, b, c, d;
565 unpack_addr (ip, &a, &b, &c, &d); /* ip is in network order */
566 sprintf (ips, "%u.%u.%u.%u", a, b, c, d);
567 if (!name || !*name) name = "<unknown>";
568 fprintf (out, "%-16s %s\n", ips, name);
573 * Create a target for a host.
576 * name - The name of the host.
579 * A newly allocated target or null if the host could not be resolved.
586 /* Local Variables */
588 ping_target *target = NULL;
590 /* Create the target */
592 if ((target = calloc(1, sizeof(ping_target))) == NULL) {
593 fprintf(stderr, "%s: Out of Memory\n", progname);
594 goto target_init_error;
596 if ((target->name = strdup(name)) == NULL) {
597 fprintf(stderr, "%s: Out of Memory\n", progname);
598 goto target_init_error;
601 /* Lookup the host */
603 if (! lookupHost(target))
604 goto target_init_error;
606 /* Don't ever use loopback (127.0.0.x) hosts */
608 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
609 unsigned long ip = iaddr->sin_addr.s_addr;
611 if ((ntohl (ip) & 0xFFFFFF00L) == 0x7f000000L) /* 127.0.0 */
614 fprintf (stderr, "%s: ignoring loopback host %s\n",
615 progname, target->name);
616 goto target_init_error;
624 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(target->address);
625 unsigned long ip = iaddr->sin_addr.s_addr;
626 fprintf (stderr, "%s: added ", progname);
627 print_host (stderr, ip, target->name);
632 /* Handle errors here */
641 * Generate a list of ping targets from the entries in a file.
644 * fname - The name of the file. This file is expected to be in the same
645 * format as /etc/hosts.
648 * A list of targets to ping or null if an error occured.
652 readPingHostsFile(char *fname)
654 /* Local Variables */
659 ping_target *list = NULL;
663 /* Make sure we in fact have a file to process */
665 if ((fname == NULL) || (fname[0] == '\0')) {
666 fprintf(stderr, "%s: invalid ping host file name\n", progname);
672 if ((fp = fopen(fname, "r")) == NULL) {
674 sprintf(msg, "%s: unable to open host file %s", progname, fname);
680 fprintf (stderr, "%s: reading file %s\n", progname, fname);
682 /* Read the file line by line */
684 while ((p = fgets(buf, LINE_MAX, fp)) != NULL) {
687 * Parse the line skipping those that start with '#'.
688 * The rest of the lines in the file should be in the same
689 * format as a /etc/hosts file. We are only concerned with
690 * the first two field, the IP address and the name
693 while ((*p == ' ') || (*p == '\t'))
698 /* Get the name and address */
701 if ((addr = strtok(buf, " ,;\t\n")) != NULL)
702 name = strtok(NULL, " ,;\t\n");
706 /* Check to see if the addr looks like an addr. If not, assume
707 the addr is a name and there is no addr. This way, we can
708 handle files whose lines have "xx.xx.xx.xx hostname" as their
709 first two tokens, and also files that have a hostname as their
710 first token (like .ssh/known_hosts and .rhosts.)
714 if (4 != sscanf(addr, "%d.%d.%d.%d%c", &i, &i, &i, &i, &c))
721 /* If the name is all digits, it's not a name. */
725 for (s = name; *s; s++)
726 if (*s < '0' || *s > '9')
731 fprintf (stderr, "%s: skipping bogus name \"%s\" (%s)\n",
732 progname, name, addr);
737 /* Create a new target using first the name then the address */
742 if (new == NULL && addr != NULL)
745 /* Add it to the list if we got one */
753 /* Close the file and return the list */
761 delete_duplicate_hosts (ping_target *list)
763 ping_target *head = list;
766 for (rest = head; rest; rest = rest->next)
768 struct sockaddr_in *i1 = (struct sockaddr_in *) &(rest->address);
769 unsigned long ip1 = i1->sin_addr.s_addr;
771 static ping_target *rest2;
772 for (rest2 = rest; rest2; rest2 = rest2->next)
774 if (rest2 && rest2->next)
776 struct sockaddr_in *i2 = (struct sockaddr_in *)
777 &(rest2->next->address);
778 unsigned long ip2 = i2->sin_addr.s_addr;
784 fprintf (stderr, "%s: deleted duplicate: ", progname);
785 print_host (stderr, ip2, rest2->next->name);
787 rest2->next = rest2->next->next;
800 * Generate a list ping targets consisting of all of the entries on
801 * the same subnet. 'base' ip is in network order; 0 means localhost.
804 * A list of all of the hosts on this net.
808 subnetHostsList(unsigned long n_base, int subnet_width)
810 unsigned long h_mask; /* host order */
811 unsigned long h_base; /* host order */
813 /* Local Variables */
815 char hostname[BUFSIZ];
816 char address[BUFSIZ];
817 struct hostent *hent;
821 ping_target *list = NULL;
823 if (subnet_width < 24)
826 "%s: pinging %lu hosts is a bad idea; please use a subnet mask of 24 bits\n"
827 " or more (255 hosts max.)\n",
828 progname, (unsigned long) (1L << (32 - subnet_width)) - 1);
831 else if (subnet_width > 30)
833 fprintf (stderr, "%s: a subnet of %d bits doesn't make sense:"
834 " try \"subnet/24\" or \"subnet/29\".\n",
835 progname, subnet_width);
841 fprintf (stderr, "%s: adding %d-bit subnet\n", progname, subnet_width);
843 /* Get our hostname */
845 if (gethostname(hostname, BUFSIZ)) {
846 fprintf(stderr, "%s: unable to get local hostname\n", progname);
850 /* Get our IP address and convert it to a string */
852 if ((hent = gethostbyname(hostname)) == NULL) {
853 fprintf(stderr, "%s: unable to lookup our IP address\n", progname);
856 strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0])));
858 /* Construct targets for all addresses in this subnet */
861 for (i = 0; i < subnet_width; i++)
862 h_mask |= (1L << (31-i));
864 /* If no base IP specified, assume localhost. */
866 n_base = pack_addr (hent->h_addr_list[0][0],
867 hent->h_addr_list[0][1],
868 hent->h_addr_list[0][2],
869 hent->h_addr_list[0][3]);
870 h_base = ntohl (n_base);
872 if (h_base == 0x7F000001L) /* 127.0.0.1 in host order */
874 unsigned int a, b, c, d;
875 unpack_addr (n_base, &a, &b, &c, &d);
877 "%s: unable to determine local subnet address: \"%s\"\n"
878 " resolves to loopback address %u.%u.%u.%u.\n",
879 progname, hostname, a, b, c, d);
883 for (i = 255; i >= 0; i--) {
884 unsigned int a, b, c, d;
885 int ip = (h_base & 0xFFFFFF00L) | i; /* host order */
887 if ((ip & h_mask) != (h_base & h_mask)) /* not in mask range at all */
889 if ((ip & ~h_mask) == 0) /* broadcast address */
891 if ((ip & ~h_mask) == ~h_mask) /* broadcast address */
894 unpack_addr (htonl (ip), &a, &b, &c, &d);
895 sprintf (address, "%u.%u.%u.%u", a, b, c, d);
899 unsigned int aa, ab, ac, ad;
900 unsigned int ma, mb, mc, md;
901 unpack_addr (htonl (h_base & h_mask), &aa, &ab, &ac, &ad);
902 unpack_addr (htonl (h_mask), &ma, &mb, &mc, &md);
904 "%s: subnet: %s (%u.%u.%u.%u & %u.%u.%u.%u / %d)\n",
911 p = address + strlen(address) + 1;
914 new = newHost(address);
927 * Initialize the ping sensor.
930 * A newly allocated ping_info structure or null if an error occured.
933 static ping_target *parse_mode (Bool ping_works_p);
939 Bool socket_initted_p = False;
941 /* Local Variables */
943 ping_info *pi = NULL; /* The new ping_info struct */
944 ping_target *pt; /* Used to count the targets */
946 /* Create the ping info structure */
948 if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) {
949 fprintf(stderr, "%s: Out of memory\n", progname);
950 goto ping_init_error;
953 /* Create the ICMP socket. Do this before dropping privs.
955 Raw sockets can only be opened by root (or setuid root), so we
956 only try to do this when the effective uid is 0.
958 We used to just always try, and notice the failure. But apparently
959 that causes "SELinux" to log spurious warnings when running with the
960 "strict" policy. So to avoid that, we just don't try unless we
963 if (geteuid() == 0 &&
964 (pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) >= 0) {
965 socket_initted_p = True;
973 pi->pid = getpid() & 0xFFFF;
975 pi->timeout = get_integer_resource("pingTimeout", "PingTimeout");
977 /* Generate a list of targets */
979 pi->targets = parse_mode (socket_initted_p);
980 pi->targets = delete_duplicate_hosts (pi->targets);
986 fprintf (stderr, "%s: Target list:\n", progname);
987 for (t = pi->targets; t; t = t->next)
989 struct sockaddr_in *iaddr = (struct sockaddr_in *) &(t->address);
990 unsigned long ip = iaddr->sin_addr.s_addr;
991 fprintf (stderr, "%s: ", progname);
992 print_host (stderr, ip, t->name);
996 /* Make sure there is something to ping */
998 if (pi->targets == NULL) {
999 goto ping_init_error;
1002 /* Count the targets */
1006 while (pt != NULL) {
1015 /* Handle initialization errors here */
1028 * pi - The ping information strcuture.
1029 * host - The name or IP address of the host to ping (in ascii).
1033 sendping(ping_info *pi, ping_target *pt)
1036 /* Local Variables */
1043 * Note, we will send the character name of the host that we are
1044 * pinging in the packet so that we don't have to keep track of the
1045 * name or do an address lookup when it comes back.
1048 int pcktsiz = sizeof(struct ICMP) + sizeof(struct timeval) +
1049 strlen(pt->name) + 1;
1051 /* Create the ICMP packet */
1053 if ((packet = (u_char *) malloc(pcktsiz)) == (void *) 0)
1054 return; /* Out of memory */
1055 icmph = (struct ICMP *) packet;
1056 ICMP_TYPE(icmph) = ICMP_ECHO;
1057 ICMP_CODE(icmph) = 0;
1058 ICMP_CHECKSUM(icmph) = 0;
1059 ICMP_ID(icmph) = pi->pid;
1060 ICMP_SEQ(icmph) = pi->seq++;
1061 # ifdef GETTIMEOFDAY_TWO_ARGS
1062 gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)],
1063 (struct timezone *) 0);
1065 gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)]);
1068 strcpy((char *) &packet[sizeof(struct ICMP) + sizeof(struct timeval)],
1070 ICMP_CHECKSUM(icmph) = checksum((u_short *)packet, pcktsiz);
1074 if ((result = sendto(pi->icmpsock, packet, pcktsiz, 0,
1075 &pt->address, sizeof(pt->address))) != pcktsiz) {
1077 char errbuf[BUFSIZ];
1078 sprintf(errbuf, "%s: error sending ping to %s", progname, pt->name);
1085 * Catch a signal and do nothing.
1088 * sig - The signal that was caught.
1098 * Compute the checksum on a ping packet.
1101 * packet - A pointer to the packet to compute the checksum for.
1102 * size - The size of the packet.
1105 * The computed checksum
1110 checksum(u_short *packet, int size)
1113 /* Local Variables */
1115 register int nleft = size;
1116 register u_short *w = packet;
1117 register int sum = 0;
1121 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1122 * sequential 16 bit words to it, and at the end, fold back all the
1123 * carry bits from the top 16 bits into the lower 16 bits.
1131 /* mop up an odd byte, if necessary */
1134 *(u_char *)(&answer) = *(u_char *)w ;
1135 *(1 + (u_char *)(&answer)) = 0;
1139 /* add back carry outs from top 16 bits to low 16 bits */
1141 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1142 sum += (sum >> 16); /* add carry */
1143 answer = ~sum; /* truncate to 16 bits */
1151 * Look for ping replies.
1153 * Retrieve all outstanding ping replies.
1156 * si - Information about the sonar.
1157 * pi - Ping information.
1158 * ttl - The time each bogie is to live on the screen
1161 * A Bogie list of all the machines that replied.
1165 getping(sonar_info *si, ping_info *pi)
1168 /* Local Variables */
1170 struct sockaddr from;
1171 unsigned int fromlen; /* Posix says socklen_t, but that's not portable */
1173 u_char packet[1024];
1175 struct timeval *then;
1182 struct sigaction sa;
1183 struct itimerval it;
1187 /* Set up a signal to interupt our wait for a packet */
1189 sigemptyset(&sa.sa_mask);
1191 sa.sa_handler = sigcatcher;
1192 if (sigaction(SIGALRM, &sa, 0) == -1) {
1194 sprintf(msg, "%s: unable to trap SIGALRM", progname);
1199 /* Set up a timer to interupt us if we don't get a packet */
1201 it.it_interval.tv_sec = 0;
1202 it.it_interval.tv_usec = 0;
1203 it.it_value.tv_sec = 0;
1204 it.it_value.tv_usec = pi->timeout;
1206 setitimer(ITIMER_REAL, &it, NULL);
1208 /* Wait for a result packet */
1210 fromlen = sizeof(from);
1211 while (! timer_expired) {
1212 tv.tv_usec=pi->timeout;
1215 /* This breaks on BSD, which uses bzero() in the definition of FD_ZERO */
1218 memset (&rfds, 0, sizeof(rfds));
1220 FD_SET(pi->icmpsock,&rfds);
1221 /* only wait a little while, in case we raced with the timer expiration.
1222 From Valentijn Sessink <valentyn@openoffice.nl> */
1223 if (select(pi->icmpsock+1, &rfds, NULL, NULL, &tv) >0) {
1224 result = recvfrom(pi->icmpsock, packet, sizeof(packet),
1225 0, &from, &fromlen);
1227 /* Check the packet */
1229 # ifdef GETTIMEOFDAY_TWO_ARGS
1230 gettimeofday(&now, (struct timezone *) 0);
1234 ip = (struct ip *) packet;
1235 iphdrlen = IP_HDRLEN(ip) << 2;
1236 icmph = (struct ICMP *) &packet[iphdrlen];
1237 then = (struct timeval *) &packet[iphdrlen + sizeof(struct ICMP)];
1240 /* Was the packet a reply?? */
1242 if (ICMP_TYPE(icmph) != ICMP_ECHOREPLY) {
1243 /* Ignore anything but ICMP Replies */
1244 continue; /* Nope */
1247 /* Was it for us? */
1249 if (ICMP_ID(icmph) != pi->pid) {
1250 /* Ignore packets not set from us */
1251 continue; /* Nope */
1254 /* Copy the name of the bogie */
1257 strdup((char *) &packet[iphdrlen +
1258 + sizeof(struct ICMP)
1259 + sizeof(struct timeval)])) == NULL) {
1260 fprintf(stderr, "%s: Out of memory\n", progname);
1264 # if 0 /* Don't need to do this -- the host names are already as
1265 resolved as they're going to get. (We stored the resolved
1266 name in the outgoing ping packet, so that same string just
1270 /* If the name is an IP addr, try to resolve it. */
1274 if (4 == sscanf(name, " %d.%d.%d.%d %c",
1275 &iip[0], &iip[1], &iip[2], &iip[3], &c))
1277 struct sockaddr_in iaddr;
1279 iaddr.sin_addr.s_addr = pack_addr (iip[0],iip[1],iip[2],iip[3]);
1281 h = gethostbyaddr ((const char *) &iaddr.sin_addr.s_addr,
1282 sizeof(iaddr.sin_addr.s_addr),
1287 if (h && h->h_name && *h->h_name)
1290 name = strdup (h->h_name);
1296 /* Create the new Bogie and add it to the list we are building */
1298 if ((new = newBogie(name, 0, si->current, si->TTL)) == NULL)
1304 float msec = delta(then, &now) / 1000.0;
1308 if (new->desc) free (new->desc);
1309 new->desc = (char *) malloc (30);
1310 if (msec > 99) sprintf (new->desc, " %.0f ms ", msec);
1311 else if (msec > 9) sprintf (new->desc, " %.1f ms ", msec);
1312 else if (msec > 1) sprintf (new->desc, " %.2f ms ", msec);
1313 else sprintf (new->desc, " %.3f ms ", msec);
1316 if (debug_p && times_p) /* print ping-like stuff to stdout */
1318 struct sockaddr_in *iaddr = (struct sockaddr_in *) &from;
1319 unsigned int a, b, c, d;
1321 char *s = strdup (new->desc);
1322 char *s2 = s, *s3 = s;
1323 while (*s2 == ' ') s2++;
1324 s3 = strchr (s2, ' ');
1327 unpack_addr (iaddr->sin_addr.s_addr, &a, &b, &c, &d);
1328 sprintf (ipstr, "%d.%d.%d.%d", a, b, c, d);
1331 "%3d bytes from %28s: "
1332 "icmp_seq=%-4d ttl=%d time=%s ms\n",
1336 ICMP_SEQ(icmph), si->TTL, s2);
1340 /* Don't put anyone *too* close to the center of the screen. */
1343 new->distance = msec * 10;
1357 * si - Sonar Information.
1358 * pi - Ping Information.
1361 * A list of hosts that replied to pings or null if there were none.
1365 ping(sonar_info *si, void *vpi)
1369 * This tries to distribute the targets evely around the field of the
1373 ping_info *pi = (ping_info *) vpi;
1374 static ping_target *ptr = NULL;
1376 int tick = si->current * -1 + 1;
1377 if ((ptr == NULL) && (tick == 1))
1380 if (pi->numtargets <= 90) {
1381 int xdrant = 90 / pi->numtargets;
1382 if ((tick % xdrant) == 0) {
1383 if (ptr != (ping_target *) 0) {
1389 } else if (pi->numtargets > 90) {
1390 if (ptr != (ping_target *) 0) {
1396 /* Get the results */
1398 return getping(si, pi);
1401 #endif /* HAVE_PING */
1404 * Calculate the difference between two timevals in microseconds.
1407 * then - The older timeval.
1408 * now - The newer timeval.
1411 * The difference between the two in microseconds.
1415 delta(struct timeval *then, struct timeval *now)
1417 return (((now->tv_sec - then->tv_sec) * 1000000) +
1418 (now->tv_usec - then->tv_usec));
1422 * Initialize the simulation mode.
1429 /* Local Variables */
1434 /* Create the simulation info structure */
1436 if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) {
1437 fprintf(stderr, "%s: Out of memory\n", progname);
1443 si->numA = get_integer_resource("teamACount", "TeamACount");
1444 if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target)))
1447 fprintf(stderr, "%s: Out of Memory\n", progname);
1450 si->teamAID = get_string_resource("teamAName", "TeamAName");
1451 for (i = 0; i < si->numA; i++) {
1452 if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4))
1455 fprintf(stderr, "%s: Out of Memory\n", progname);
1458 sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1);
1459 si->teamA[i].nexttick = random() % 90;
1460 si->teamA[i].nextdist = random() % 100;
1461 si->teamA[i].movedonsweep = -1;
1466 si->numB = get_integer_resource("teamBCount", "TeamBCount");
1467 if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target)))
1470 fprintf(stderr, "%s: Out of Memory\n", progname);
1473 si->teamBID = get_string_resource("teamBName", "TeamBName");
1474 for (i = 0; i < si->numB; i++) {
1475 if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4))
1478 fprintf(stderr, "%s: Out of Memory\n", progname);
1481 sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1);
1482 si->teamB[i].nexttick = random() % 90;
1483 si->teamB[i].nextdist = random() % 100;
1484 si->teamB[i].movedonsweep = -1;
1493 * Creates and returns a drawing mask for the scope:
1494 * mask out anything outside of the disc.
1497 scope_mask (Display *dpy, Window win, sonar_info *si)
1500 Pixmap mask = XCreatePixmap(dpy, win, si->width, si->height, 1);
1501 GC gc = XCreateGC (dpy, mask, 0, &gcv);
1502 XSetFunction (dpy, gc, GXclear);
1503 XFillRectangle (dpy, mask, gc, 0, 0, si->width, si->height);
1504 XSetFunction (dpy, gc, GXset);
1505 XFillArc(dpy, mask, gc, si->minx, si->miny,
1506 si->maxx - si->minx, si->maxy - si->miny,
1513 reshape (sonar_info *si)
1515 XWindowAttributes xgwa;
1517 XGetWindowAttributes(si->dpy, si->win, &xgwa);
1518 si->width = xgwa.width;
1519 si->height = xgwa.height;
1520 si->centrex = si->width / 2;
1521 si->centrey = si->height / 2;
1522 si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10;
1523 si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10;
1524 si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10;
1525 si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10;
1526 si->radius = si->maxx - si->centrex;
1528 /* Install the clip mask... */
1529 mask = scope_mask (si->dpy, si->win, si);
1530 XSetClipMask(si->dpy, si->text, mask);
1531 XSetClipMask(si->dpy, si->erase, mask);
1532 XFreePixmap (si->dpy, mask); /* it's been copied into the GCs */
1536 * Initialize the Sonar.
1539 * dpy - The X display.
1540 * win - The X window;
1543 * A sonar_info strcuture or null if memory allocation problems occur.
1547 init_sonar(Display *dpy, Window win)
1550 /* Local Variables */
1553 XWindowAttributes xwa;
1557 double s1, s2, v1, v2;
1559 /* Create the Sonar information structure */
1561 if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) {
1562 fprintf(stderr, "%s: Out of memory\n", progname);
1566 /* Initialize the structure for the current environment */
1572 XGetWindowAttributes(dpy, win, &xwa);
1573 si->cmap = xwa.colormap;
1580 if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font")))
1582 ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) {
1583 fprintf(stderr, "%s: can't load an appropriate font\n", progname);
1587 /* Get the delay between animation frames */
1589 si->delay = get_integer_resource ("delay", "Integer");
1591 if (si->delay < 0) si->delay = 0;
1592 si->TTL = get_integer_resource("ttl", "TTL");
1594 /* Create the Graphics Contexts that will be used to draw things */
1597 get_pixel_resource ("sweepColor", "SweepColor", dpy, si->cmap);
1598 si->hi = XCreateGC(dpy, win, GCForeground, &gcv);
1599 gcv.font = si->font->fid;
1600 si->text = XCreateGC(dpy, win, GCForeground|GCFont, &gcv);
1601 gcv.foreground = get_pixel_resource("scopeColor", "ScopeColor",
1603 si->erase = XCreateGC (dpy, win, GCForeground, &gcv);
1604 gcv.foreground = get_pixel_resource("gridColor", "GridColor",
1606 si->grid = XCreateGC (dpy, win, GCForeground, &gcv);
1610 /* Compute pixel values for fading text on the display */
1612 XParseColor(dpy, si->cmap,
1613 get_string_resource("textColor", "TextColor"), &start);
1614 XParseColor(dpy, si->cmap,
1615 get_string_resource("scopeColor", "ScopeColor"), &end);
1617 rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
1618 rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2);
1620 si->text_steps = get_integer_resource("textSteps", "TextSteps");
1621 if (si->text_steps < 0 || si->text_steps > 255)
1622 si->text_steps = 10;
1624 si->text_colors = (XColor *) calloc(si->text_steps, sizeof(XColor));
1625 make_color_ramp (dpy, si->cmap,
1628 si->text_colors, &si->text_steps,
1629 False, True, False);
1631 /* Compute the pixel values for the fading sweep */
1633 XParseColor(dpy, si->cmap,
1634 get_string_resource("sweepColor", "SweepColor"), &start);
1636 rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
1638 si->sweep_degrees = get_integer_resource("sweepDegrees", "Degrees");
1639 if (si->sweep_degrees <= 0) si->sweep_degrees = 20;
1640 if (si->sweep_degrees > 350) si->sweep_degrees = 350;
1642 si->sweep_segs = get_integer_resource("sweepSegments", "SweepSegments");
1643 if (si->sweep_segs < 1 || si->sweep_segs > 255)
1644 si->sweep_segs = 255;
1646 si->sweep_colors = (XColor *) calloc(si->sweep_segs, sizeof(XColor));
1647 make_color_ramp (dpy, si->cmap,
1650 si->sweep_colors, &si->sweep_segs,
1651 False, True, False);
1653 if (si->sweep_segs <= 0)
1662 * Update the location of a simulated bogie.
1666 updateLocation(sim_target *t)
1671 xtick = (int) (random() % 3) - 1;
1672 xdist = (int) (random() % 11) - 5;
1673 if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0))
1674 t->nexttick += xtick;
1676 t->nexttick -= xtick;
1677 if (((t->nextdist + xdist) < 100) && ((t->nextdist+xdist) >= 0))
1678 t->nextdist += xdist;
1680 t->nextdist -= xdist;
1684 * The simulator. This uses information in the sim_info to simulate a bunch
1685 * of bogies flying around on the screen.
1689 * TODO: It would be cool to have the two teams chase each other around and
1694 simulator(sonar_info *si, void *vinfo)
1697 /* Local Variables */
1703 sim_info *info = (sim_info *) vinfo;
1707 for (i = 0; i < info->numA; i++) {
1708 t = &info->teamA[i];
1709 if ((t->movedonsweep != si->sweepnum) &&
1710 (t->nexttick == (si->current * -1))) {
1711 new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL);
1716 t->movedonsweep = si->sweepnum;
1722 for (i = 0; i < info->numB; i++) {
1723 t = &info->teamB[i];
1724 if ((t->movedonsweep != si->sweepnum) &&
1725 (t->nexttick == (si->current * -1))) {
1726 new = newBogie(strdup(t->name), t->nextdist, si->current, si->TTL);
1731 t->movedonsweep = si->sweepnum;
1741 * Compute the X coordinate of the label.
1744 * si - The sonar info block.
1745 * label - The label that will be drawn.
1746 * x - The x coordinate of the bogie.
1749 * The x coordinate of the start of the label.
1753 computeStringX(sonar_info *si, const char *label, int x)
1756 int width = XTextWidth(si->font, label, strlen(label));
1757 return x - (width / 2);
1761 * Compute the Y coordinate of the label.
1764 * si - The sonar information.
1765 * y - The y coordinate of the bogie.
1768 * The y coordinate of the start of the label.
1772 computeStringY(sonar_info *si, int y)
1775 int fheight = si->font->ascent /* + si->font->descent */;
1780 * Draw a Bogie on the radar screen.
1783 * si - Sonar Information.
1784 * draw - A flag to indicate if the bogie should be drawn or erased.
1785 * name - The name of the bogie.
1786 * degrees - The number of degrees that it should apprear at.
1787 * distance - The distance the object is from the centre.
1788 * ttl - The time this bogie has to live.
1789 * age - The time this bogie has been around.
1793 DrawBogie(sonar_info *si, int draw, const char *name, const char *desc,
1794 int degrees, int distance, int ttl, int age)
1797 /* Local Variables */
1801 int ox = si->centrex;
1802 int oy = si->centrey;
1805 /* Compute the coordinates of the object */
1808 distance = (log((double) distance) / 10.0) * si->radius;
1809 x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578));
1810 y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578));
1812 /* Set up the graphics context */
1816 /* Here we attempt to compute the distance into the total life of
1817 * object that we currently are. This distance is used against
1818 * the total lifetime to compute a fraction which is the index of
1819 * the color to draw the bogie.
1822 if (si->current <= degrees)
1823 delta = (si->current - degrees) * -1;
1825 delta = 90 + (degrees - si->current);
1826 delta += (age * 90);
1827 index = (si->text_steps - 1) * ((float) delta / (90.0 * (float) ttl));
1829 XSetForeground(si->dpy, gc, si->text_colors[index].pixel);
1834 /* Draw (or erase) the Bogie */
1836 XFillArc(si->dpy, si->win, gc, x, y, 5, 5, 0, 360 * 64);
1838 x += 3; /* move away from the dot */
1840 y = computeStringY(si, y);
1841 XDrawString(si->dpy, si->win, gc,
1842 computeStringX(si, name, x), y,
1843 name, strlen(name));
1847 y = computeStringY(si, y);
1848 XDrawString(si->dpy, si->win, gc,
1849 computeStringX(si, desc, x), y,
1850 desc, strlen(desc));
1856 * Draw the sonar grid.
1859 * si - Sonar information block.
1863 drawGrid(sonar_info *si)
1866 /* Local Variables */
1869 int width = si->maxx - si->minx;
1870 int height = si->maxy - si->miny;
1872 /* Draw the circles */
1874 XDrawArc(si->dpy, si->win, si->grid, si->minx - 10, si->miny - 10,
1875 width + 20, height + 20, 0, (360 * 64));
1877 XDrawArc(si->dpy, si->win, si->grid, si->minx, si->miny,
1878 width, height, 0, (360 * 64));
1880 XDrawArc(si->dpy, si->win, si->grid,
1881 (int) (si->minx + (.166 * width)),
1882 (int) (si->miny + (.166 * height)),
1883 (unsigned int) (.666 * width), (unsigned int)(.666 * height),
1886 XDrawArc(si->dpy, si->win, si->grid,
1887 (int) (si->minx + (.333 * width)),
1888 (int) (si->miny + (.333 * height)),
1889 (unsigned int) (.333 * width), (unsigned int) (.333 * height),
1892 /* Draw the radial lines */
1894 for (i = 0; i < 360; i += 10)
1896 XDrawLine(si->dpy, si->win, si->grid, si->centrex, si->centrey,
1897 (int) (si->centrex +
1898 (si->radius + 10) * (cos((double) i / 57.29578))),
1899 (int) (si->centrey -
1900 (si->radius + 10)*(sin((double) i / 57.29578))));
1902 XDrawLine(si->dpy, si->win, si->grid,
1903 (int) (si->centrex + si->radius *
1904 (cos((double) i / 57.29578))),
1905 (int) (si->centrey - si->radius *
1906 (sin((double) i / 57.29578))),
1907 (int) (si->centrex +
1908 (si->radius + 10) * (cos((double) i / 57.29578))),
1909 (int) (si->centrey -
1910 (si->radius + 10) * (sin((double) i / 57.29578))));
1914 * Update the Sonar scope.
1917 * si - The Sonar information.
1918 * bl - A list of bogies to add to the scope.
1922 Sonar(sonar_info *si, Bogie *bl)
1925 /* Local Variables */
1930 /* Check for expired tagets and remove them from the visible list */
1933 for (bp = si->visible; bp != NULL; bp = (bp ? bp->next : 0)) {
1936 * Remove it from the visible list if it's expired or we have
1937 * a new target with the same name.
1942 if (((bp->tick == si->current) && (++bp->age >= bp->ttl)) ||
1943 (findNode(bl, bp->name) != NULL)) {
1944 DrawBogie(si, 0, bp->name, bp->desc, bp->tick,
1945 bp->distance, bp->ttl, bp->age);
1947 si->visible = bp->next;
1949 prev->next = bp->next;
1956 /* Draw the sweep */
1959 int seg_deg = (si->sweep_degrees * 64) / si->sweep_segs;
1960 int start_deg = si->current * 4 * 64;
1961 if (seg_deg <= 0) seg_deg = 1;
1962 for (i = 0; i < si->sweep_segs; i++) {
1963 XSetForeground(si->dpy, si->hi, si->sweep_colors[i].pixel);
1964 XFillArc(si->dpy, si->win, si->hi, si->minx, si->miny,
1965 si->maxx - si->minx, si->maxy - si->miny,
1966 start_deg + (i * seg_deg),
1970 /* Remove the trailing wedge the sonar */
1971 XFillArc(si->dpy, si->win, si->erase, si->minx, si->miny,
1972 si->maxx - si->minx, si->maxy - si->miny,
1973 start_deg + (i * seg_deg),
1977 /* Move the new targets to the visible list */
1979 for (bp = bl; bp != (Bogie *) 0; bp = bl) {
1981 bp->next = si->visible;
1985 /* Draw the visible targets */
1987 for (bp = si->visible; bp != NULL; bp = bp->next) {
1988 if (bp->age < bp->ttl) /* grins */
1989 DrawBogie(si, 1, bp->name, bp->desc,
1990 bp->tick, bp->distance, bp->ttl,bp->age);
1993 /* Redraw the grid */
1999 static ping_target *
2000 parse_mode (Bool ping_works_p)
2002 char *source = get_string_resource ("ping", "Ping");
2006 ping_target *hostlist = 0;
2008 if (!source) source = strdup("");
2010 if (!*source || !strcmp (source, "default"))
2013 if (ping_works_p) /* if root or setuid, ping will work. */
2014 source = strdup("subnet/29,/etc/hosts");
2017 source = strdup("simulation");
2021 end = source + strlen(source);
2028 unsigned int n0=0, n1=0, n2=0, n3=0, m=0;
2030 # endif /* HAVE_PING */
2034 *next != ',' && *next != ' ' && *next != '\t' && *next != '\n';
2041 fprintf (stderr, "%s: parsing %s\n", progname, token);
2043 if (!strcmp (token, "simulation"))
2049 "%s: this program must be setuid to root for `ping mode' to work.\n"
2050 " Running in `simulation mode' instead.\n",
2056 if ((4 == sscanf (token, "%u.%u.%u/%u %c", &n0,&n1,&n2, &m,&d)) ||
2057 (5 == sscanf (token, "%u.%u.%u.%u/%u %c", &n0,&n1,&n2,&n3,&m,&d)))
2059 /* subnet: A.B.C.D/M
2062 unsigned long ip = pack_addr (n0, n1, n2, n3);
2063 new = subnetHostsList(ip, m);
2065 else if (4 == sscanf (token, "%u.%u.%u.%u %c", &n0, &n1, &n2, &n3, &d))
2069 new = newHost (token);
2071 else if (!strcmp (token, "subnet"))
2073 new = subnetHostsList(0, 24);
2075 else if (1 == sscanf (token, "subnet/%u %c", &m, &dummy))
2077 new = subnetHostsList(0, m);
2079 else if (*token == '.' || *token == '/' || !stat (token, &st))
2083 new = readPingHostsFile (token);
2087 /* not an existant file - must be a host name
2089 new = newHost (token);
2094 ping_target *nn = new;
2095 while (nn && nn->next)
2097 nn->next = hostlist;
2102 #endif /* HAVE_PING */
2105 while (token < end &&
2106 (*token == ',' || *token == ' ' ||
2107 *token == '\t' || *token == '\n'))
2116 handle_events (sonar_info *si)
2118 while (XPending (si->dpy))
2121 XNextEvent (si->dpy, &event);
2123 if (event.xany.type == ConfigureNotify)
2125 XClearWindow (si->dpy, si->win);
2129 screenhack_handle_event (si->dpy, &event);
2136 * Main screen saver hack.
2139 * dpy - The X display.
2140 * win - The X window.
2144 screenhack(Display *dpy, Window win)
2147 /* Local Variables */
2150 struct timeval start, finish;
2154 debug_p = get_boolean_resource ("debug", "Debug");
2155 resolve_p = get_boolean_resource ("resolve", "Resolve");
2156 times_p = get_boolean_resource ("showTimes", "ShowTimes");
2160 sensor_info = (void *) init_ping();
2161 # else /* !HAVE_PING */
2163 parse_mode (0); /* just to check argument syntax */
2164 # endif /* !HAVE_PING */
2169 if ((sensor_info = (void *) init_sim()) == NULL)
2173 if ((si = init_sonar(dpy, win)) == (sonar_info *) 0)
2181 /* Call the sensor and display the results */
2183 # ifdef GETTIMEOFDAY_TWO_ARGS
2184 gettimeofday(&start, (struct timezone *) 0);
2186 gettimeofday(&start);
2188 bl = sensor(si, sensor_info);
2191 /* Set up and sleep for the next one */
2193 si->current = (si->current - 1) % 90;
2194 if (si->current == 0)
2197 # ifdef GETTIMEOFDAY_TWO_ARGS
2198 gettimeofday(&finish, (struct timezone *) 0);
2200 gettimeofday(&finish);
2202 sleeptime = si->delay - delta(&start, &finish);