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)
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. */
24 #include <sys/param.h>
25 #include <sys/socket.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>
38 #include <arpa/inet.h>
51 #include <ping_impl.h>
53 static char short_options
[] = "VLhc:dfi:l:np:qRrs:t:v";
54 static struct option long_options
[] =
57 {"version", no_argument
, NULL
, 'V'},
58 {"license", no_argument
, NULL
, 'L'},
59 {"help", no_argument
, NULL
, 'h'},
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'},
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
));
90 size_t data_length
= PING_DATALEN
;
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
)
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
));
120 ping_set_sockopt (ping
, SO_BROADCAST
, (char *)&one
, sizeof (one
));
122 /* Reset root privileges */
125 /* Parse command line */
126 while ((c
= getopt_long (argc
, argv
, short_options
, long_options
, NULL
))
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");
152 ping_set_count (ping
, atoi (optarg
));
156 ping_set_sockopt (ping
, SO_DEBUG
, &one
, sizeof (one
));
160 ping_set_sockopt (ping
, SO_DONTROUTE
, &one
, sizeof (one
));
164 options
|= OPT_INTERVAL
;
165 ping_set_interval (ping
, atoi (optarg
));
169 decode_pattern (optarg
, &pattern_len
, pattern
);
174 data_length
= atoi (optarg
);
178 options
|= OPT_NUMERIC
;
182 options
|= OPT_QUIET
;
186 options
|= OPT_RROUTE
;
190 options
|= OPT_VERBOSE
;
196 fprintf (stderr
, "ping: option not allowed: --preload\n");
199 preload
= strtoul (optarg
, &p
, 0);
200 if (*p
|| preload
> INT_MAX
)
202 fprintf (stderr
, "ping: invalid preload value (%s)\n", optarg
);
210 fprintf (stderr
, "ping: option not allowed: --flood\n");
213 options
|= OPT_FLOOD
;
214 setbuf (stdout
, (char *)NULL
);
218 decode_type (optarg
);
222 decode_type ("echo");
226 decode_type ("timestamp");
230 decode_type ("address");
233 case ICMP_ROUTERDISCOVERY
:
234 decode_type ("router");
238 fprintf (stderr
, "%c: not implemented\n", c
);
251 init_data_buffer (patptr
, pattern_len
);
253 return (*ping_type
)(argc
, argv
);
257 init_data_buffer (u_char
*pat
, int len
)
262 if (data_length
== 0)
264 data_buffer
= malloc (data_length
);
267 fprintf (stderr
, "ping: out of memory\n");
272 for (p
= data_buffer
; p
< data_buffer
+ data_length
; p
++)
281 for (i
= 0; i
< data_length
; i
++)
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
;
297 else if (strcasecmp (optarg
, "router") == 0)
298 ping_type
= ping_router
;
302 fprintf (stderr
, "unsupported packet type: %s\n", optarg
);
308 decode_pattern (const char *text
, int *pattern_len
, u_char
*pattern_data
)
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
);
324 int volatile stop
= 0;
333 ping_run (PING
*ping
, int (*finish
)())
337 struct timeval timeout
;
338 struct timeval last
, intvl
, now
;
339 struct timeval
*t
= NULL
;
342 signal (SIGINT
, sig_int
);
344 fdmax
= ping
->ping_fd
+1;
349 if (options
& OPT_FLOOD
)
352 intvl
.tv_usec
= 10000;
356 intvl
.tv_sec
= ping
->ping_interval
;
360 gettimeofday (&last
, NULL
);
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;
378 while (timeout
.tv_usec
>= 1000000)
380 timeout
.tv_usec
-= 1000000;
384 if (timeout
.tv_sec
< 0)
385 timeout
.tv_sec
= timeout
.tv_usec
= 0;
387 if ((n
= select (fdmax
, &fdset
, NULL
, NULL
, &timeout
)) < 0)
390 perror ("ping: select");
395 len
= ping_recv (ping
);
398 gettimeofday (&now
, NULL
);
401 if (ping
->ping_count
&& ping
->ping_num_recv
>= ping
->ping_count
)
406 if (!ping
->ping_count
|| ping
->ping_num_recv
< ping
->ping_count
)
409 if (!(options
& OPT_QUIET
) && options
& OPT_FLOOD
)
420 intvl
.tv_sec
= MAXWAIT
;
422 gettimeofday (&last
, NULL
);
431 send_echo (PING
*ping
)
435 if (PING_TIMING (data_length
))
438 gettimeofday (&tv
, NULL
);
439 ping_set_data (ping
, &tv
, 0, sizeof (tv
));
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
);
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!");
463 printf ("%d%% packet loss",
464 (int) (((ping
->ping_num_xmit
- ping
->ping_num_recv
) * 100) /
465 ping
->ping_num_xmit
));
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\
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"
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"
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
);