--- ../inetutils/ping/ping.c 2006-11-17 19:27:29.000000000 +0530 +++ ping/ping.c 2007-03-28 02:43:08.000000000 +0530 @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -100,7 +101,175 @@ static int send_echo (PING * ping); #define MIN_USER_INTERVAL (200000/PING_PRECISION) -char *program_name; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +const char *argp_program_version = "ping (" PACKAGE_NAME ") " PACKAGE_VERSION; + +const char args_doc[] = "ADDRESS"; +const char doc[] = "Send ICMP ECHO_REQUEST packets to network hosts."; + +static struct argp_option options[] = { + {"", '', 0, OPTION_DOC, "Options controlling ICMP request types:"}, + {"echo", ICMP_ECHO, 0, 0, "Send ICMP_ECHO requests (default)"}, + {"address*", ICMP_ADDRESS, 0, 0, "Send ICMP_ADDRESS packets"}, + {"timestamp", ICMP_TIMESTAMP, 0, 0, "Send ICMP_TIMESTAMP packets"}, + {"router", ICMP_ROUTERDISCOVERY, 0, 0, "Send ICMP_ROUTERDISCOVERY packets"}, + {"", '', 0, OPTION_DOC, "Options valid for all request types:"}, + {"count", 'c', "N", 0, "Stop after sending N packets (default: %d)"}, + {"debug", 'd', 0, 0, "Set the SO_DEBUG option"}, + {"interval", 'i', "N", 0, "Wait N seconds between sending each packet"}, + {"numeric", 'n', 0, 0, "Do not resolve host addresses"}, + {"ignore-routing", 'r', 0, 0, "Send directly to a host on an attached network"}, + {"verbose", 'v', 0, 0, "Verbose output"}, + {"", '', 0, OPTION_DOC, "Options valid for --echo requests:"}, + {"flood*", 'f', 0, 0, "Flood ping"}, + {"preload", 'l', "N", 0, "Send N packets as fast as possible before falling into\n + normal mode of behavior"}, + {"pattern", 'p', "PAT", 0, "Fill ICMP packet with given pattern (hex)"}, + {"quiet", 'q', 0, 0, "Quiet output"}, + {"route", 'r', 0, 0, "Record route"}, + {"size", 's', "N", 0, "Set number of data octets to send"}, + {0} +}; + +struct arguments +{ + char *args[1]; + u_char *patptr; + int count; + int socket_type; + int pattern; + int size; + unsigned int options; + unsigned long preload; + size_t interval; + int (*ping_type) (int argc, char **argv); +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + char *endptr; + struct arguments *arguments = state->input; + + arguments->patptr = NULL; + arguments->size = PING_DATALEN; + arguments->preload = 0; + arguments->interval = 0; + arguments->ping_type = ping_echo; + switch (key) + { + case 'c': + arguments->count = ping_cvt_number (arg, 0, 1); + break; + + case 'd': + arguments->socket_type = SO_DEBUG; + break; + + case 'r': + arguments->socket_type = SO_DONTROUTE; + break; + + case 'i': + arguments->interval = strtod (arg, &endptr); + if (*endptr) + { + fprintf (stderr, "Invalid value (`%s' near `%s')\n", + arg, endptr); + exit (1); + } + + if ((arguments->interval *= PING_PRECISION) < MIN_USER_INTERVAL) + { + fprintf (stderr, "Option value too small: %s\n", arg); + exit (1); + } + arguments->options |= OPT_INTERVAL; + break; + + case 'p': + decode_pattern (arg, &pattern_len, pattern); + arguments->patptr = pattern; + break; + + case 's': + arguments->size = ping_cvt_number (arg, PING_MAX_DATALEN, 1); + break; + + case 'n': + arguments->options |= OPT_NUMERIC; + break; + + case 'q': + arguments->options |= OPT_QUIET; + break; + + case 'R': + arguments->options |= OPT_RROUTE; + break; + + case 'v': + arguments->options |= OPT_VERBOSE; + break; + + case 'l': + arguments->preload = strtoul (arg, &endptr, 0); + if (*endptr || arguments->preload > INT_MAX) + { + fprintf (stderr, "ping: invalid preload value (%s)\n", arg); + exit (1); + } + break; + + case 'f': + arguments->options |= OPT_FLOOD; + break; + + case 't': + arguments->ping_type = decode_type (arg); + break; + + case ICMP_ECHO: + arguments->ping_type = decode_type ("echo"); + break; + + case ICMP_TIMESTAMP: + arguments->ping_type = decode_type ("timestamp"); + break; + + case ICMP_ADDRESS: + arguments->ping_type = decode_type ("address"); + break; + + case ICMP_ROUTERDISCOVERY: + arguments->ping_type = decode_type ("router"); + break; + + case ARGP_KEY_NO_ARGS: + argp_usage (state); + break; + + case ARGP_KEY_ARG: + if (state->arg_num >= 1) + /* Too many arguments. */ + argp_usage (state); + arguments->args[state->arg_num] = arg; + break; + + case ARGP_KEY_END: + if (state->arg_num < 1) + /* Not enough arguments. */ + argp_usage (state); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = {options, parse_opt, args_doc, doc}; int main (int argc, char **argv) @@ -117,8 +286,6 @@ main (int argc, char **argv) int socket_type = 0; size_t interval = 0; - program_name = argv[0]; - if (getuid () == 0) is_root = true; @@ -302,9 +469,11 @@ main (int argc, char **argv) -void +int (*) (int argc, char **argv) decode_type (const char *optarg) { + int (*ping_type) (int argc, char **argv); + if (strcasecmp (optarg, "echo") == 0) ping_type = ping_echo; else if (strcasecmp (optarg, "timestamp") == 0) @@ -320,6 +489,8 @@ decode_type (const char *optarg) fprintf (stderr, "unsupported packet type: %s\n", optarg); exit (1); } + + return ping_type; } int volatile stop = 0;