X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=ping.c;h=50c7ce6e64f98344996b7369adaee3eab9afe725;hb=5165fbed639916e0fde15a827241b21981be7934;hp=fd5e33c032a218d079f32db47b86d509a553a7c3;hpb=2285f367e220af9bda9f544945007725a02032dd;p=oweals%2Fbusybox.git diff --git a/ping.c b/ping.c index fd5e33c03..50c7ce6e6 100644 --- a/ping.c +++ b/ping.c @@ -1,5 +1,6 @@ +/* vi: set sw=4 ts=4: */ /* - * $Id: ping.c,v 1.3 1999/12/08 04:23:30 andersen Exp $ + * $Id: ping.c,v 1.38 2001/02/20 06:14:08 andersen Exp $ * Mini ping implementation for busybox * * Copyright (C) 1999 by Randolph Chung @@ -30,7 +31,6 @@ * Original copyright notice is retained at the end of this file. */ -#include "internal.h" #include #include #include @@ -46,13 +46,100 @@ #include #include #include +#include +#include +#include +#include "busybox.h" + + +/* It turns out that libc5 doesn't have proper icmp support + * built into it header files, so we have to supplement it */ +#if ! defined __GLIBC__ && ! defined __UCLIBC__ +typedef unsigned int socklen_t; + +static const int ICMP_MINLEN = 8; /* abs minimum */ + +struct icmp_ra_addr +{ + u_int32_t ira_addr; + u_int32_t ira_preference; +}; + + +struct icmp +{ + u_int8_t icmp_type; /* type of message, see below */ + u_int8_t icmp_code; /* type sub code */ + u_int16_t icmp_cksum; /* ones complement checksum of struct */ + union + { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* gateway address */ + struct ih_idseq /* echo datagram */ + { + u_int16_t icd_id; + u_int16_t icd_seq; + } ih_idseq; + u_int32_t ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu + { + u_int16_t ipm_void; + u_int16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv + { + u_int8_t irt_num_addrs; + u_int8_t irt_wpa; + u_int16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union + { + struct + { + u_int32_t its_otime; + u_int32_t its_rtime; + u_int32_t its_ttime; + } id_ts; + struct + { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + u_int32_t id_mask; + u_int8_t id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; +#endif -#define DEFDATALEN 56 -#define MAXIPLEN 60 -#define MAXICMPLEN 76 -#define MAXPACKET 65468 +static const int DEFDATALEN = 56; +static const int MAXIPLEN = 60; +static const int MAXICMPLEN = 76; +static const int MAXPACKET = 65468; #define MAX_DUP_CHK (8 * 128) -#define MAXWAIT 10 +static const int MAXWAIT = 10; +static const int PINGINTERVAL = 1; /* second */ #define O_QUIET (1 << 0) @@ -62,278 +149,403 @@ #define CLR(bit) (A(bit) &= (~B(bit))) #define TST(bit) (A(bit) & B(bit)) -static const char* ping_usage = "ping [OPTION]... host\n\n" -"Options:\n" -"\t-q\t\tQuiet mode, only displays output at start and when finished.\n" -"\t-c COUNT\tSend only COUNT pings.\n"; +static void ping(const char *host); + +/* common routines */ +static int in_cksum(unsigned short *buf, int sz) +{ + int nleft = sz; + int sum = 0; + unsigned short *w = buf; + unsigned short ans = 0; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + if (nleft == 1) { + *(unsigned char *) (&ans) = *(unsigned char *) w; + sum += ans; + } + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + ans = ~sum; + return (ans); +} +/* simple version */ +#ifdef BB_FEATURE_SIMPLE_PING +static char *hostname = NULL; + +static void noresp(int ign) +{ + printf("No response from %s\n", hostname); + exit(0); +} + +static void ping(const char *host) +{ + struct hostent *h; + struct sockaddr_in pingaddr; + struct icmp *pkt; + int pingsock, c; + char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; + + if ((pingsock = socket(AF_INET, SOCK_RAW, 1)) < 0) /* 1 == ICMP */ + perror_msg_and_die("creating a raw socket"); + + /* drop root privs if running setuid */ + setuid(getuid()); + + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); + + pingaddr.sin_family = AF_INET; + if (!(h = gethostbyname(host))) { + error_msg("unknown host %s", host); + exit(1); + } + memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); + hostname = h->h_name; + + pkt = (struct icmp *) packet; + memset(pkt, 0, sizeof(packet)); + pkt->icmp_type = ICMP_ECHO; + pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); + + c = sendto(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); + + if (c < 0 || c != sizeof(packet)) + perror_msg_and_die("sendto"); + + signal(SIGALRM, noresp); + alarm(5); /* give the host 5000ms to respond */ + /* listen for replies */ + while (1) { + struct sockaddr_in from; + size_t fromlen = sizeof(from); + + if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &from, &fromlen)) < 0) { + if (errno == EINTR) + continue; + perror_msg("recvfrom"); + continue; + } + if (c >= 76) { /* ip + icmp */ + struct iphdr *iphdr = (struct iphdr *) packet; + + pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ + if (pkt->icmp_type == ICMP_ECHOREPLY) + break; + } + } + printf("%s is alive!\n", hostname); + return; +} + +extern int ping_main(int argc, char **argv) +{ + argc--; + argv++; + if (argc < 1) + show_usage(); + ping(*argv); + return EXIT_SUCCESS; +} + +#else /* ! BB_FEATURE_SIMPLE_PING */ +/* full(er) version */ static char *hostname = NULL; static struct sockaddr_in pingaddr; static int pingsock = -1; +static int datalen; /* intentionally uninitialized to work around gcc bug */ + static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0; static int myid = 0, options = 0; static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0; static char rcvd_tbl[MAX_DUP_CHK / 8]; -static void pingstats(int); static void sendping(int); +static void pingstats(int); static void unpack(char *, int, struct sockaddr_in *); -static void ping(char *); -static int in_cksum(unsigned short *, int); /**************************************************************************/ -static int in_cksum(unsigned short *buf, int sz) +static void pingstats(int junk) { - int nleft = sz; - int sum = 0; - unsigned short *w = buf; - unsigned short ans = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(unsigned char *)(&ans) = *(unsigned char *)w; - sum += ans; - } - - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - ans = ~sum; - return(ans); -} - -static void pingstats(int ign) { - signal(SIGINT, SIG_IGN); - - printf("\n--- %s ping statistics ---\n", hostname); - printf("%ld packets transmitted, ", ntransmitted); - printf("%ld packets received, ", nreceived); - if (nrepeats) - printf("%ld duplicates, ", nrepeats); - if (ntransmitted) - printf("%ld%% packet loss\n", - (ntransmitted - nreceived)*100/ntransmitted); - if (nreceived) - printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", - tmin/10, tmin%10, - (tsum/(nreceived+nrepeats))/10, - (tsum/(nreceived+nrepeats))%10, - tmax/10, tmax%10); - exit(0); + int status; + + signal(SIGINT, SIG_IGN); + + printf("\n--- %s ping statistics ---\n", hostname); + printf("%ld packets transmitted, ", ntransmitted); + printf("%ld packets received, ", nreceived); + if (nrepeats) + printf("%ld duplicates, ", nrepeats); + if (ntransmitted) + printf("%ld%% packet loss\n", + (ntransmitted - nreceived) * 100 / ntransmitted); + if (nreceived) + printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", + tmin / 10, tmin % 10, + (tsum / (nreceived + nrepeats)) / 10, + (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); + if (nreceived != 0) + status = EXIT_SUCCESS; + else + status = EXIT_FAILURE; + exit(status); } -static void sendping(int ign) +static void sendping(int junk) { - struct icmp *pkt; - int i; - char packet[DEFDATALEN + 8]; - - pkt = (struct icmp *)packet; - - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_code = 0; - pkt->icmp_cksum = 0; - pkt->icmp_seq = ntransmitted++; - pkt->icmp_id = myid; - CLR(pkt->icmp_seq % MAX_DUP_CHK); - - gettimeofday((struct timeval *)&packet[8], NULL); - pkt->icmp_cksum = in_cksum((unsigned short *)pkt, sizeof(packet)); - - i = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *)&pingaddr, sizeof(struct sockaddr_in)); - - if (i < 0 || i != sizeof(packet)) { - if (i < 0) perror("ping"); - fprintf(stderr, "ping wrote %d chars; %d expected\n", i, sizeof(packet)); - exit(1); - } - - signal(SIGALRM, sendping); - if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next */ - alarm(1); - } else { /* done, wait for the last ping to come back */ - /* todo, don't necessarily need to wait so long... */ - signal(SIGALRM, pingstats); - alarm(MAXWAIT); - } + struct icmp *pkt; + int i; + char packet[datalen + 8]; + + pkt = (struct icmp *) packet; + + pkt->icmp_type = ICMP_ECHO; + pkt->icmp_code = 0; + pkt->icmp_cksum = 0; + pkt->icmp_seq = ntransmitted++; + pkt->icmp_id = myid; + CLR(pkt->icmp_seq % MAX_DUP_CHK); + + gettimeofday((struct timeval *) &packet[8], NULL); + pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); + + i = sendto(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); + + if (i < 0) + perror_msg_and_die("sendto"); + else if ((size_t)i != sizeof(packet)) + error_msg_and_die("ping wrote %d chars; %d expected", i, + (int)sizeof(packet)); + + signal(SIGALRM, sendping); + if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ + alarm(PINGINTERVAL); + } else { /* done, wait for the last ping to come back */ + /* todo, don't necessarily need to wait so long... */ + signal(SIGALRM, pingstats); + alarm(MAXWAIT); + } } - -static void unpack(char *buf, int sz, struct sockaddr_in *from) + +static char *icmp_type_name (int id) { - struct icmp *icmppkt; - struct iphdr *iphdr; - struct timeval tv, *tp; - int hlen, dupflag; - unsigned long triptime; - - gettimeofday(&tv, NULL); - - /* check IP header */ - iphdr = (struct iphdr *)buf; - hlen = iphdr->ihl << 2; - /* discard if too short */ - if (sz < (DEFDATALEN + ICMP_MINLEN)) return; - - sz -= hlen; - icmppkt = (struct icmp *)(buf + hlen); - - if (icmppkt->icmp_type == ICMP_ECHOREPLY) { - if (icmppkt->icmp_id != myid) return; /* not our ping */ - ++nreceived; - tp = (struct timeval *)icmppkt->icmp_data; - - if ((tv.tv_usec -= tp->tv_usec) < 0) { - --tv.tv_sec; - tv.tv_usec += 1000000; - } - tv.tv_sec -= tp->tv_sec; - - triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); - tsum += triptime; - if (triptime < tmin) tmin = triptime; - if (triptime > tmax) tmax = triptime; - - if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { - ++nrepeats; - --nreceived; - dupflag = 1; - } else { - SET(icmppkt->icmp_seq % MAX_DUP_CHK); - dupflag = 0; + switch (id) { + case ICMP_ECHOREPLY: return "Echo Reply"; + case ICMP_DEST_UNREACH: return "Destination Unreachable"; + case ICMP_SOURCE_QUENCH: return "Source Quench"; + case ICMP_REDIRECT: return "Redirect (change route)"; + case ICMP_ECHO: return "Echo Request"; + case ICMP_TIME_EXCEEDED: return "Time Exceeded"; + case ICMP_PARAMETERPROB: return "Parameter Problem"; + case ICMP_TIMESTAMP: return "Timestamp Request"; + case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; + case ICMP_INFO_REQUEST: return "Information Request"; + case ICMP_INFO_REPLY: return "Information Reply"; + case ICMP_ADDRESS: return "Address Mask Request"; + case ICMP_ADDRESSREPLY: return "Address Mask Reply"; + default: return "unknown ICMP type"; } +} - if (options & O_QUIET) return; - - printf("%d bytes from %s: icmp_seq=%u", sz, - inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), - icmppkt->icmp_seq); - printf(" ttl=%d", iphdr->ttl); - printf(" time=%lu.%lu ms", triptime/10, triptime%10); - if (dupflag) printf(" (DUP!)"); - printf("\n"); - } else { - fprintf(stderr, "Warning: unknown ICMP packet received (not echo-reply)\n"); - } +static void unpack(char *buf, int sz, struct sockaddr_in *from) +{ + struct icmp *icmppkt; + struct iphdr *iphdr; + struct timeval tv, *tp; + int hlen, dupflag; + unsigned long triptime; + + gettimeofday(&tv, NULL); + + /* check IP header */ + iphdr = (struct iphdr *) buf; + hlen = iphdr->ihl << 2; + /* discard if too short */ + if (sz < (datalen + ICMP_MINLEN)) + return; + + sz -= hlen; + icmppkt = (struct icmp *) (buf + hlen); + + if (icmppkt->icmp_id != myid) + return; /* not our ping */ + + if (icmppkt->icmp_type == ICMP_ECHOREPLY) { + ++nreceived; + tp = (struct timeval *) icmppkt->icmp_data; + + if ((tv.tv_usec -= tp->tv_usec) < 0) { + --tv.tv_sec; + tv.tv_usec += 1000000; + } + tv.tv_sec -= tp->tv_sec; + + triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); + tsum += triptime; + if (triptime < tmin) + tmin = triptime; + if (triptime > tmax) + tmax = triptime; + + if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(icmppkt->icmp_seq % MAX_DUP_CHK); + dupflag = 0; + } + + if (options & O_QUIET) + return; + + printf("%d bytes from %s: icmp_seq=%u", sz, + inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), + icmppkt->icmp_seq); + printf(" ttl=%d", iphdr->ttl); + printf(" time=%lu.%lu ms", triptime / 10, triptime % 10); + if (dupflag) + printf(" (DUP!)"); + printf("\n"); + } else + if (icmppkt->icmp_type != ICMP_ECHO) + error_msg("Warning: Got ICMP %d (%s)", + icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type)); } -static void ping(char *host) +static void ping(const char *host) { - struct protoent *proto; - struct hostent *h; - char buf[MAXHOSTNAMELEN]; - char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; - int sockopt; - - if (!(proto = getprotobyname("icmp"))) { - fprintf(stderr, "ping: unknown protocol icmp\n"); - exit(1); - } - if ((pingsock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { - if (errno == EPERM) { - fprintf(stderr, "ping: permission denied. (are you root?)\n"); - } else { - perror("ping"); + struct protoent *proto; + struct hostent *h; + char buf[MAXHOSTNAMELEN]; + char packet[datalen + MAXIPLEN + MAXICMPLEN]; + int sockopt; + + proto = getprotobyname("icmp"); + /* if getprotobyname failed, just silently force + * proto->p_proto to have the correct value for "icmp" */ + if ((pingsock = socket(AF_INET, SOCK_RAW, + (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */ + if (errno == EPERM) + error_msg_and_die("permission denied. (are you root?)"); + else + perror_msg_and_die("creating a raw socket"); } - exit(1); - } -#ifdef SUID_BUSYBOX - setuid(getuid()); -#endif - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - pingaddr.sin_family = AF_INET; - if (inet_aton(host, &pingaddr.sin_addr)) { - hostname = host; - } else { - if (!(h = gethostbyname(host))) { - fprintf(stderr, "ping: unknown host %s\n", host); - exit(1); - } + /* drop root privs if running setuid */ + setuid(getuid()); + + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); + + pingaddr.sin_family = AF_INET; + if (!(h = gethostbyname(host))) { + error_msg("unknown host %s", host); + exit(1); + } if (h->h_addrtype != AF_INET) { - fprintf(stderr, "ping: unknown address type; only AF_INET is currently supported.\n"); - exit(1); + error_msg("unknown address type; only AF_INET is currently supported."); + exit(1); } - - pingaddr.sin_family = AF_INET; /* h->h_addrtype */ - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - strncpy(buf, h->h_name, sizeof(buf)-1); + + pingaddr.sin_family = AF_INET; /* h->h_addrtype */ + memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); + strncpy(buf, h->h_name, sizeof(buf) - 1); hostname = buf; - } - - /* enable broadcast pings */ - sockopt = 1; - setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *)&sockopt, sizeof(sockopt)); - - /* set recv buf for broadcast pings */ - sockopt = 48 * 1024; - setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *)&sockopt, sizeof(sockopt)); - - printf("PING %s (%s): %d data bytes\n", - hostname, inet_ntoa(*(struct in_addr *)&pingaddr.sin_addr.s_addr), - DEFDATALEN); - - signal(SIGINT, pingstats); - - /* start the ping's going ... */ - sendping(0); - - /* listen for replies */ - while (1) { - struct sockaddr_in from; - size_t fromlen = sizeof(from); - int c; - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *)&from, &fromlen)) < 0) { - if (errno == EINTR) continue; - perror("ping"); - continue; + + /* enable broadcast pings */ + sockopt = 1; + setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, + sizeof(sockopt)); + + /* set recv buf for broadcast pings */ + sockopt = 48 * 1024; + setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, + sizeof(sockopt)); + + printf("PING %s (%s): %d data bytes\n", + hostname, + inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), + datalen); + + signal(SIGINT, pingstats); + + /* start the ping's going ... */ + sendping(0); + + /* listen for replies */ + while (1) { + struct sockaddr_in from; + socklen_t fromlen = (socklen_t) sizeof(from); + int c; + + if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &from, &fromlen)) < 0) { + if (errno == EINTR) + continue; + perror_msg("recvfrom"); + continue; + } + unpack(packet, c, &from); + if (pingcount > 0 && nreceived >= pingcount) + break; } - unpack(packet, c, &from); - if (pingcount > 0 && nreceived >= pingcount) break; - } - pingstats(0); + pingstats(0); } extern int ping_main(int argc, char **argv) { - argc--; - argv++; - options = 0; - /* Parse any options */ - if (argc < 1) usage(ping_usage); - - while (**argv == '-') { - while (*++(*argv)) - switch (**argv) { - case 'c': - argc--; argv++; - if (argc < 1) usage(ping_usage); - pingcount = atoi(*argv); - break; - case 'q': - options |= O_QUIET; - break; - default: - usage(ping_usage); - } + char *thisarg; + + datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ + argc--; argv++; - } - - if (argc < 1) usage(ping_usage); + options = 0; + /* Parse any options */ + while (argc >= 1 && **argv == '-') { + thisarg = *argv; + thisarg++; + switch (*thisarg) { + case 'q': + options |= O_QUIET; + break; + case 'c': + if (--argc <= 0) + show_usage(); + argv++; + pingcount = atoi(*argv); + break; + case 's': + if (--argc <= 0) + show_usage(); + argv++; + datalen = atoi(*argv); + break; + default: + show_usage(); + } + argc--; + argv++; + } + if (argc < 1) + show_usage(); - myid = getpid() & 0xFFFF; - ping(*(argv++)); - exit( TRUE); + myid = getpid() & 0xFFFF; + ping(*argv); + return EXIT_SUCCESS; } +#endif /* ! BB_FEATURE_SIMPLE_PING */ /* * Copyright (c) 1989 The Regents of the University of California. @@ -350,10 +562,10 @@ extern int ping_main(int argc, char **argv) * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * + * 3. + * * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -370,5 +582,3 @@ extern int ping_main(int argc, char **argv) * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - -