Upstream update.
[shishi.git] / extra / inetutils / ping / ping.c
blob788a7a5c3920859315132cb57db84cc553155280
1 /* Copyright (C) 1998,2001, 2002 Free Software Foundation, Inc.
3 This file is part of GNU Inetutils.
5 GNU Inetutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 GNU Inetutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNU Inetutils; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include <sys/param.h>
25 #include <sys/socket.h>
26 #include <sys/file.h>
27 #include <sys/time.h>
28 #include <signal.h>
30 #include <netinet/in_systm.h>
31 #include <netinet/in.h>
32 #include <netinet/ip.h>
33 /*#include <netinet/ip_icmp.h> -- deliberately not including this */
34 #ifdef HAVE_NETINET_IP_VAR_H
35 # include <netinet/ip_var.h>
36 #endif
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <limits.h>
48 #include "getopt.h"
49 #include <icmp.h>
50 #include <ping.h>
51 #include <ping_impl.h>
53 static char short_options[] = "VLhc:dfi:l:np:qRrs:t:v";
54 static struct option long_options[] =
56 /* Help options */
57 {"version", no_argument, NULL, 'V'},
58 {"license", no_argument, NULL, 'L'},
59 {"help", no_argument, NULL, 'h'},
60 /* Common options */
61 {"count", required_argument, NULL, 'c'},
62 {"debug", no_argument, NULL, 'd'},
63 {"ignore-routing", no_argument, NULL, 'r'},
64 {"size", required_argument, NULL, 's'},
65 {"interval",required_argument, NULL, 'i'},
66 {"numeric", no_argument, NULL, 'n'},
67 {"verbose", no_argument, NULL, 'v'},
68 /* Packet types */
69 {"type", required_argument, NULL, 't'},
70 {"echo", no_argument, NULL, ICMP_ECHO},
71 {"timestamp",no_argument, NULL, ICMP_TIMESTAMP},
72 {"address", no_argument, NULL, ICMP_ADDRESS},
73 {"router", no_argument, NULL, ICMP_ROUTERDISCOVERY},
74 /* echo-specific options */
75 {"flood", no_argument, NULL, 'f'},
76 {"preload", required_argument, NULL, 'l'},
77 {"pattern", required_argument, NULL, 'p'},
78 {"quiet", no_argument, NULL, 'q'},
79 {"route", no_argument, NULL, 'R'},
80 {NULL, no_argument, NULL, 0}
83 extern int ping_echo __P ((int argc, char **argv));
84 extern int ping_timestamp __P ((int argc, char **argv));
85 extern int ping_address __P ((int argc, char **argv));
86 extern int ping_router __P ((int argc, char **argv));
88 PING *ping;
89 u_char *data_buffer;
90 size_t data_length = PING_DATALEN;
91 unsigned options;
92 unsigned long preload = 0;
93 int (*ping_type) __P ((int argc, char **argv)) = ping_echo;
96 static void show_usage (void);
97 static void show_license (void);
98 static void decode_pattern (const char *text, int *pattern_len,
99 u_char *pattern_data);
100 static void decode_type (const char *optarg);
101 static void init_data_buffer (u_char *pat, int len);
102 static int send_echo (PING *ping);
105 main (int argc, char **argv)
107 int c;
108 char *p;
109 int one = 1;
110 u_char pattern[16];
111 int pattern_len = 16;
112 u_char *patptr = NULL;
113 int is_root = getuid () == 0;
115 if ((ping = ping_init (ICMP_ECHO, getpid ())) == NULL)
117 fprintf (stderr, "can't init ping: %s\n", strerror (errno));
118 exit (1);
120 ping_set_sockopt (ping, SO_BROADCAST, (char *)&one, sizeof (one));
122 /* Reset root privileges */
123 setuid (getuid ());
125 /* Parse command line */
126 while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
127 != EOF)
129 switch (c)
131 case 'V':
132 printf ("ping - %s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
133 printf ("Copyright (C) 1998,2001 Free Software Foundation, Inc.\n");
134 printf ("%s comes with ABSOLUTELY NO WARRANTY.\n", PACKAGE_NAME);
135 printf ("You may redistribute copies of %s\n", PACKAGE_NAME);
136 printf ("under the terms of the GNU General Public License.\n");
137 printf ("For more information about these matters, ");
138 printf ("see the files named COPYING.\n");
139 exit (0);
140 break;
142 case 'L':
143 show_license ();
144 exit (0);
146 case 'h':
147 show_usage ();
148 exit (0);
149 break;
151 case 'c':
152 ping_set_count (ping, atoi (optarg));
153 break;
155 case 'd':
156 ping_set_sockopt (ping, SO_DEBUG, &one, sizeof (one));
157 break;
159 case 'r':
160 ping_set_sockopt (ping, SO_DONTROUTE, &one, sizeof (one));
161 break;
163 case 'i':
164 options |= OPT_INTERVAL;
165 ping_set_interval (ping, atoi (optarg));
166 break;
168 case 'p':
169 decode_pattern (optarg, &pattern_len, pattern);
170 patptr = pattern;
171 break;
173 case 's':
174 data_length = atoi (optarg);
175 break;
177 case 'n':
178 options |= OPT_NUMERIC;
179 break;
181 case 'q':
182 options |= OPT_QUIET;
183 break;
185 case 'R':
186 options |= OPT_RROUTE;
187 break;
189 case 'v':
190 options |= OPT_VERBOSE;
191 break;
193 case 'l':
194 if (!is_root)
196 fprintf (stderr, "ping: option not allowed: --preload\n");
197 exit (1);
199 preload = strtoul (optarg, &p, 0);
200 if (*p || preload > INT_MAX)
202 fprintf (stderr, "ping: invalid preload value (%s)\n", optarg);
203 exit (1);
205 break;
207 case 'f':
208 if (!is_root)
210 fprintf (stderr, "ping: option not allowed: --flood\n");
211 exit (1);
213 options |= OPT_FLOOD;
214 setbuf (stdout, (char *)NULL);
215 break;
217 case 't':
218 decode_type (optarg);
219 break;
221 case ICMP_ECHO:
222 decode_type ("echo");
223 break;
225 case ICMP_TIMESTAMP:
226 decode_type ("timestamp");
227 break;
229 case ICMP_ADDRESS:
230 decode_type ("address");
231 break;
233 case ICMP_ROUTERDISCOVERY:
234 decode_type ("router");
235 break;
237 default:
238 fprintf (stderr, "%c: not implemented\n", c);
239 exit (1);
243 argc -= optind;
244 argv += optind;
245 if (argc == 0)
247 show_usage ();
248 exit (0);
251 init_data_buffer (patptr, pattern_len);
253 return (*ping_type)(argc, argv);
256 void
257 init_data_buffer (u_char *pat, int len)
259 int i = 0;
260 u_char *p;
262 if (data_length == 0)
263 return;
264 data_buffer = malloc (data_length);
265 if (!data_buffer)
267 fprintf (stderr, "ping: out of memory\n");
268 exit (1);
270 if (pat)
272 for (p = data_buffer; p < data_buffer + data_length; p++)
274 *p = pat[i];
275 if (i++ >= len)
276 i = 0;
279 else
281 for (i = 0; i < data_length; i++)
282 data_buffer[i] = i;
287 void
288 decode_type (const char *optarg)
290 if (strcasecmp (optarg, "echo") == 0)
291 ping_type = ping_echo;
292 else if (strcasecmp (optarg, "timestamp") == 0)
293 ping_type = ping_timestamp;
294 else if (strcasecmp (optarg, "address") == 0)
295 ping_type = ping_address;
296 #if 0
297 else if (strcasecmp (optarg, "router") == 0)
298 ping_type = ping_router;
299 #endif
300 else
302 fprintf (stderr, "unsupported packet type: %s\n", optarg);
303 exit (1);
307 void
308 decode_pattern (const char *text, int *pattern_len, u_char *pattern_data)
310 int i, c, off;
312 for (i = 0; *text && i < *pattern_len; i++)
314 if (sscanf (text, "%2x%n", &c, &off) != 1)
316 fprintf (stderr, "ping: error in pattern near %s\n", text);
317 exit (1);
319 text += off;
321 *pattern_len = i;
324 int volatile stop = 0;
326 RETSIGTYPE
327 sig_int (int signal)
329 stop = 1;
333 ping_run (PING *ping, int (*finish)())
335 fd_set fdset;
336 int fdmax;
337 struct timeval timeout;
338 struct timeval last, intvl, now;
339 struct timeval *t = NULL;
340 int finishing = 0;
342 signal (SIGINT, sig_int);
344 fdmax = ping->ping_fd+1;
346 while (preload--)
347 send_echo (ping);
349 if (options & OPT_FLOOD)
351 intvl.tv_sec = 0;
352 intvl.tv_usec = 10000;
354 else
356 intvl.tv_sec = ping->ping_interval;
357 intvl.tv_usec = 0;
360 gettimeofday (&last, NULL);
361 send_echo (ping);
363 while (!stop)
365 int n, len;
367 FD_ZERO (&fdset);
368 FD_SET (ping->ping_fd, &fdset);
369 gettimeofday (&now, NULL);
370 timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
371 timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
373 while (timeout.tv_usec < 0)
375 timeout.tv_usec += 1000000;
376 timeout.tv_sec--;
378 while (timeout.tv_usec >= 1000000)
380 timeout.tv_usec -= 1000000;
381 timeout.tv_sec++;
384 if (timeout.tv_sec < 0)
385 timeout.tv_sec = timeout.tv_usec = 0;
387 if ((n = select (fdmax, &fdset, NULL, NULL, &timeout)) < 0)
389 if (errno != EINTR)
390 perror ("ping: select");
391 continue;
393 else if (n == 1)
395 len = ping_recv (ping);
396 if (t == 0)
398 gettimeofday (&now, NULL);
399 t = &now;
401 if (ping->ping_count && ping->ping_num_recv >= ping->ping_count)
402 break;
404 else
406 if (!ping->ping_count || ping->ping_num_recv < ping->ping_count)
408 send_echo (ping);
409 if (!(options & OPT_QUIET) && options & OPT_FLOOD)
411 putchar ('.');
414 else if (finishing)
415 break;
416 else
418 finishing = 1;
420 intvl.tv_sec = MAXWAIT;
422 gettimeofday (&last, NULL);
425 if (finish)
426 return (*finish)();
427 return 0;
431 send_echo (PING *ping)
433 int off = 0;
435 if (PING_TIMING (data_length))
437 struct timeval tv;
438 gettimeofday (&tv, NULL);
439 ping_set_data (ping, &tv, 0, sizeof (tv));
440 off += sizeof (tv);
442 if (data_buffer)
443 ping_set_data (ping, data_buffer, off,
444 data_length > PING_HEADER_LEN ?
445 data_length-PING_HEADER_LEN : data_length);
446 return ping_xmit (ping);
450 ping_finish ()
452 fflush (stdout);
453 printf ("--- %s ping statistics ---\n", ping->ping_hostname);
454 printf ("%ld packets transmitted, ", ping->ping_num_xmit);
455 printf ("%ld packets received, ", ping->ping_num_recv);
456 if (ping->ping_num_rept)
457 printf ("+%ld duplicates, ", ping->ping_num_rept);
458 if (ping->ping_num_xmit)
460 if (ping->ping_num_recv > ping->ping_num_xmit)
461 printf ("-- somebody's printing up packets!");
462 else
463 printf ("%d%% packet loss",
464 (int) (((ping->ping_num_xmit - ping->ping_num_recv) * 100) /
465 ping->ping_num_xmit));
468 printf ("\n");
469 return 0;
472 void
473 show_usage (void)
475 printf ("\
476 Usage: ping [OPTION]... [ADDRESS]...\n\
478 Informational options:\n\
479 -h, --help display this help and exit\n\
480 -L, --license display license and exit\n\
481 -V, --version output version information and exit\n\
482 Options controlling ICMP request types:\n\
483 --echo Send ICMP_ECHO requests (default)\n\
484 --address Send ICMP_ADDRESS packets\n\
485 --timestamp Send ICMP_TIMESTAMP packets\n\
486 --router Send ICMP_ROUTERDISCOVERY packets\n\
487 Options valid for all request types:\n\
488 -c, --count N stop after sending N packets\n\
489 -d, --debug set the SO_DEBUG option\n\
490 -i, --interval N wait N seconds between sending each packet\n\
491 -n, --numeric do not resolve host addresses\n\
492 -r, --ignore-routing send directly to a host on an attached network\n\
493 -v, --verbose verbose output\n\
494 Options valid for --echo requests:\n\
495 * -f, --flood flood ping \n\
496 * -l, --preload N send N packets as fast as possible before falling into\n\
497 normal mode of behavior\n\
498 -p, --pattern PAT fill ICMP packet with given pattern (hex)\n\
499 -q, --quiet quiet output\n\
500 -R, --route record route\n\
501 -s, --size N set number of data octets to send\n\
503 Options marked with an * are available only to super-user\n\
505 report bugs to " PACKAGE_BUGREPORT ".\n\
509 void
510 show_license (void)
512 static char license_text[] =
513 " This program is free software; you can redistribute it and/or modify\n"
514 " it under the terms of the GNU General Public License as published by\n"
515 " the Free Software Foundation; either version 2, or (at your option)\n"
516 " any later version.\n"
517 "\n"
518 " This program is distributed in the hope that it will be useful,\n"
519 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
520 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
521 " GNU General Public License for more details.\n"
522 "\n"
523 " You should have received a copy of the GNU General Public License\n"
524 " along with this program; if not, write to the Free Software\n"
525 " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
526 printf ("%s", license_text);