Fix kbuild bugs noticed by Bernhard Fischer <rep.nop@aon.at>
[oweals/busybox.git] / networking / ping.c
index ed52abf048418fd7095ed5e81565b7b621328d47..782b801c80d3f10cd7f082ac742ec3c5b431aded 100644 (file)
@@ -15,9 +15,8 @@
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/file.h>
-#include <sys/time.h>
 #include <sys/times.h>
-#include <sys/signal.h>
+#include <signal.h>
 
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <stdlib.h>
 #include "busybox.h"
 
-
-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)
-static const int MAXWAIT = 10;
-static const int PINGINTERVAL = 1;             /* second */
+enum {
+       DEFDATALEN = 56,
+       MAXIPLEN = 60,
+       MAXICMPLEN = 76,
+       MAXPACKET = 65468,
+       MAX_DUP_CHK = (8 * 128),
+       MAXWAIT = 10,
+       PINGINTERVAL = 1                /* second */
+};
 
 #define O_QUIET         (1 << 0)
 
@@ -77,7 +77,8 @@ static int in_cksum(unsigned short *buf, int sz)
 
 /* simple version */
 #ifndef CONFIG_FEATURE_FANCY_PING
-static char *hostname = NULL;
+static char *hostname;
+
 static void noresp(int ign)
 {
        printf("No response from %s\n", hostname);
@@ -106,11 +107,13 @@ static void ping(const char *host)
        pkt->icmp_type = ICMP_ECHO;
        pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
 
-       c = sendto(pingsock, packet, sizeof(packet), 0,
+       c = sendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 0,
                           (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
 
-       if (c < 0 || c != sizeof(packet))
+       if (c < 0) {
+               if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);
                bb_perror_msg_and_die("sendto");
+       }
 
        signal(SIGALRM, noresp);
        alarm(5);                                       /* give the host 5000ms to respond */
@@ -134,11 +137,12 @@ static void ping(const char *host)
                                break;
                }
        }
+       if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);
        printf("%s is alive!\n", hostname);
        return;
 }
 
-extern int ping_main(int argc, char **argv)
+int ping_main(int argc, char **argv)
 {
        argc--;
        argv++;
@@ -151,18 +155,16 @@ extern int ping_main(int argc, char **argv)
 #else /* ! CONFIG_FEATURE_FANCY_PING */
 /* full(er) version */
 static struct sockaddr_in pingaddr;
+static struct sockaddr_in sourceaddr;
 static int pingsock = -1;
-static int datalen; /* intentionally uninitialized to work around gcc bug */
+static unsigned datalen; /* intentionally uninitialized to work around gcc bug */
 
-static long ntransmitted, nreceived, nrepeats, pingcount;
+static unsigned long ntransmitted, nreceived, nrepeats, pingcount;
 static int myid, options;
 static unsigned long tmin = ULONG_MAX, tmax, tsum;
 static char rcvd_tbl[MAX_DUP_CHK / 8];
 
-#ifndef CONFIG_FEATURE_FANCY_PING6
-static
-#endif
-       struct hostent *hostent;
+static struct hostent *hostent;
 
 static void sendping(int);
 static void pingstats(int);
@@ -177,12 +179,12 @@ static void pingstats(int junk)
        signal(SIGINT, SIG_IGN);
 
        printf("\n--- %s ping statistics ---\n", hostent->h_name);
-       printf("%ld packets transmitted, ", ntransmitted);
-       printf("%ld packets received, ", nreceived);
+       printf("%lu packets transmitted, ", ntransmitted);
+       printf("%lu packets received, ", nreceived);
        if (nrepeats)
-               printf("%ld duplicates, ", nrepeats);
+               printf("%lu duplicates, ", nrepeats);
        if (ntransmitted)
-               printf("%ld%% packet loss\n",
+               printf("%lu%% packet loss\n",
                           (ntransmitted - nreceived) * 100 / ntransmitted);
        if (nreceived)
                printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
@@ -200,7 +202,7 @@ static void sendping(int junk)
 {
        struct icmp *pkt;
        int i;
-       char packet[datalen + sizeof(struct icmp)];
+       char packet[datalen + ICMP_MINLEN];
 
        pkt = (struct icmp *) packet;
 
@@ -233,23 +235,23 @@ static void sendping(int junk)
        }
 }
 
-static char *icmp_type_name (int id)
+static char *icmp_type_name(int id)
 {
        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";
+       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";
        }
 }
 
@@ -263,22 +265,21 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from)
 
        gettimeofday(&tv, NULL);
 
-       /* check IP header */
-       iphdr = (struct iphdr *) buf;
-       hlen = iphdr->ihl << 2;
        /* discard if too short */
        if (sz < (datalen + ICMP_MINLEN))
                return;
 
+       /* check IP header */
+       iphdr = (struct iphdr *) buf;
+       hlen = iphdr->ihl << 2;
        sz -= hlen;
        icmppkt = (struct icmp *) (buf + hlen);
-
        if (icmppkt->icmp_id != myid)
-           return;                             /* not our ping */
+               return;                         /* not our ping */
 
        if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
                u_int16_t recv_seq = ntohs(icmppkt->icmp_seq);
-           ++nreceived;
+               ++nreceived;
                tp = (struct timeval *) icmppkt->icmp_data;
 
                if ((tv.tv_usec -= tp->tv_usec) < 0) {
@@ -313,11 +314,11 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from)
                printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
                if (dupflag)
                        printf(" (DUP!)");
-               printf("\n");
+               puts("");
        } else
                if (icmppkt->icmp_type != ICMP_ECHO)
-                       bb_error_msg("Warning: Got ICMP %d (%s)",
-                                       icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
+                       bb_error_msg("warning: got ICMP %d (%s)",
+                                       icmppkt->icmp_type, icmp_type_name(icmppkt->icmp_type));
        fflush(stdout);
 }
 
@@ -328,12 +329,16 @@ static void ping(const char *host)
 
        pingsock = create_icmp_socket();
 
+       if (sourceaddr.sin_addr.s_addr) {
+               xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr));
+       }
+
        memset(&pingaddr, 0, sizeof(struct sockaddr_in));
 
        pingaddr.sin_family = AF_INET;
        hostent = xgethostbyname(host);
        if (hostent->h_addrtype != AF_INET)
-               bb_error_msg_and_die("unknown address type; only AF_INET is currently supported.");
+               bb_error_msg_and_die("unknown address type; only AF_INET is currently supported");
 
        memcpy(&pingaddr.sin_addr, hostent->h_addr, sizeof(pingaddr.sin_addr));
 
@@ -347,10 +352,14 @@ static void ping(const char *host)
        setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
                           sizeof(sockopt));
 
-       printf("PING %s (%s): %d data bytes\n",
-                  hostent->h_name,
-                  inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr),
-                  datalen);
+       printf("PING %s (%s)",
+                       hostent->h_name,
+                       inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr));
+       if (sourceaddr.sin_addr.s_addr) {
+               printf(" from %s",
+                       inet_ntoa(*(struct in_addr *) &sourceaddr.sin_addr.s_addr));
+       }
+       printf(": %d data bytes\n", datalen);
 
        signal(SIGINT, pingstats);
 
@@ -377,7 +386,28 @@ static void ping(const char *host)
        pingstats(0);
 }
 
-extern int ping_main(int argc, char **argv)
+/* TODO: consolidate ether-wake.c, dnsd.c, ifupdown.c, nslookup.c
+ * versions of below thing. BTW we have far too many "%u.%u.%u.%u" too...
+*/
+static int parse_nipquad(const char *str, struct sockaddr_in* addr)
+{
+       char dummy;
+       unsigned i1, i2, i3, i4;
+       if (sscanf(str, "%u.%u.%u.%u%c",
+                          &i1, &i2, &i3, &i4, &dummy) == 4
+       && ( (i1|i2|i3|i4) <= 0xff )
+       ) {
+               uint8_t* ptr = (uint8_t*)&addr->sin_addr;
+               ptr[0] = i1;
+               ptr[1] = i2;
+               ptr[2] = i3;
+               ptr[3] = i4;
+               return 0;
+       }
+       return 1; /* error */
+}
+
+int ping_main(int argc, char **argv)
 {
        char *thisarg;
 
@@ -385,7 +415,6 @@ extern int ping_main(int argc, char **argv)
 
        argc--;
        argv++;
-       options = 0;
        /* Parse any options */
        while (argc >= 1 && **argv == '-') {
                thisarg = *argv;
@@ -396,15 +425,27 @@ extern int ping_main(int argc, char **argv)
                        break;
                case 'c':
                        if (--argc <= 0)
-                               bb_show_usage();
+                               bb_show_usage();
                        argv++;
-                       pingcount = atoi(*argv);
+                       pingcount = xatoul(*argv);
                        break;
                case 's':
                        if (--argc <= 0)
-                               bb_show_usage();
+                               bb_show_usage();
+                       argv++;
+                       datalen = xatou16(*argv);
+                       break;
+               case 'I':
+                       if (--argc <= 0)
+                               bb_show_usage();
                        argv++;
-                       datalen = atoi(*argv);
+/* ping6 accepts iface too:
+                       if_index = if_nametoindex(*argv);
+                       if (!if_index) ...
+   make it true for ping too. TODO.
+*/
+                       if (parse_nipquad(*argv, &sourceaddr))
+                               bb_show_usage();
                        break;
                default:
                        bb_show_usage();
@@ -415,7 +456,7 @@ extern int ping_main(int argc, char **argv)
        if (argc < 1)
                bb_show_usage();
 
-       myid = getpid() & 0xFFFF;
+       myid = (int16_t) getpid();
        ping(*argv);
        return EXIT_SUCCESS;
 }