Compile get_terminal_width_height
[oweals/busybox.git] / libbb / interface.c
index ff7970321f8501ce67168a9ee74334da437bda06..28007f4437121950294da9e1a504170dc62fd4cd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * stolen from net-tools-1.59 and stripped down for busybox by 
- *                     Erik Andersen <andersee@debian.org>
+ *                     Erik Andersen <andersen@codepoet.org>
  *
  * Heavily modified by Manuel Novoa III       Mar 12, 2001
  *
@@ -15,7 +15,7 @@
  *              that either displays or sets the characteristics of
  *              one or more of the system's networking interfaces.
  *
- * Version:     $Id: interface.c,v 1.12 2002/11/28 10:20:45 bug1 Exp $
+ * Version:     $Id: interface.c,v 1.20 2003/08/29 11:34:08 bug1 Exp $
  *
  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  *              and others.  Copyright 1993 MicroWalt Corporation
 #undef HAVE_AFECONET
 #undef HAVE_AFASH
 
-#ifdef CONFIG_FEATURE_IPV6
-# define HAVE_AFINET6 1
-#else
-# undef HAVE_AFINET6
-#endif
-
 /* 
  * 
  * Device Hardware types.
 #include <fcntl.h>
 #include <ctype.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include "libbb.h"
 
+#ifdef CONFIG_FEATURE_IPV6
+# define HAVE_AFINET6 1
+#else
+# undef HAVE_AFINET6
+#endif
+
 #define _(x) x
 #define _PATH_PROCNET_DEV               "/proc/net/dev"
 #define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
 #define new(p) ((p) = xcalloc(1,sizeof(*(p))))
 #define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
 
-static int procnetdev_vsn = 1;
-
-/* Ugh.  But libc5 doesn't provide POSIX types.  */
-#include <asm/types.h>
-
-
 #ifdef HAVE_HWSLIP
-#include <linux/if_slip.h>
+#include <net/if_slip.h>
 #endif
 
 #if HAVE_AFINET6
@@ -105,7 +100,7 @@ static int procnetdev_vsn = 1;
 
 struct in6_ifreq {
        struct in6_addr ifr6_addr;
-       __u32 ifr6_prefixlen;
+       uint32_t ifr6_prefixlen;
        unsigned int ifr6_ifindex;
 };
 
@@ -619,7 +614,7 @@ static int aftrans_opt(const char *arg)
                        if (strcmp(tmp1, paft->alias))
                                continue;
                        if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
-                               error_msg(_("Too many address family arguments."));
+                               bb_error_msg(_("Too many address family arguments."));
                                return (0);
                        }
                        if (paft->flag)
@@ -630,7 +625,7 @@ static int aftrans_opt(const char *arg)
                        break;
                }
                if (!paft->alias) {
-                       error_msg(_("Unknown address family `%s'."), tmp1);
+                       bb_error_msg(_("Unknown address family `%s'."), tmp1);
                        return (1);
                }
                tmp1 = tmp2;
@@ -693,7 +688,7 @@ static struct aftype *get_aftype(const char *name)
                afp++;
        }
        if (strchr(name, ','))
-               error_msg(_("Please don't supply more than one address family."));
+               bb_error_msg(_("Please don't supply more than one address family."));
        return (NULL);
 }
 #endif                                                 /* KEEP_UNUSED */
@@ -888,7 +883,7 @@ static int sockets_open(int family)
                        sfd = af->fd;
        }
        if (sfd < 0) {
-               error_msg(_("No usable address families found."));
+               bb_error_msg(_("No usable address families found."));
        }
        return sfd;
 }
@@ -960,7 +955,7 @@ static int if_readconf(void)
           (as of 2.1.128) */
        skfd2 = get_socket_for_af(AF_INET);
        if (skfd2 < 0) {
-               perror_msg(("warning: no inet socket available: %s\n"));
+               bb_perror_msg(("warning: no inet socket available"));
                /* Try to soldier on with whatever socket we can get hold of.  */
                skfd2 = sockets_open(0);
                if (skfd2 < 0)
@@ -1024,71 +1019,76 @@ static char *get_name(char *name, char *p)
        return p;
 }
 
-static int get_dev_fields(char *bp, struct interface *ife)
+/* If scanf supports size qualifiers for %n conversions, then we can
+ * use a modified fmt that simply stores the position in the fields
+ * having no associated fields in the proc string.  Of course, we need
+ * to zero them again when we're done.  But that is smaller than the
+ * old approach of multiple scanf occurrences with large numbers of
+ * args. */
+
+/* static const char *ss_fmt[] = { */
+/*     "%Ln%Lu%lu%lu%lu%lu%ln%ln%Ln%Lu%lu%lu%lu%lu%lu", */
+/*     "%Lu%Lu%lu%lu%lu%lu%ln%ln%Lu%Lu%lu%lu%lu%lu%lu", */
+/*     "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu" */
+/* }; */
+
+       /* Lie about the size of the int pointed to for %n. */
+#if INT_MAX == LONG_MAX
+static const char *ss_fmt[] = {
+       "%n%Lu%u%u%u%u%n%n%n%Lu%u%u%u%u%u",
+       "%Lu%Lu%u%u%u%u%n%n%Lu%Lu%u%u%u%u%u",
+       "%Lu%Lu%u%u%u%u%u%u%Lu%Lu%u%u%u%u%u%u"
+};
+#else
+static const char *ss_fmt[] = {
+       "%n%Lu%lu%lu%lu%lu%n%n%n%Lu%lu%lu%lu%lu%lu",
+       "%Lu%Lu%lu%lu%lu%lu%n%n%Lu%Lu%lu%lu%lu%lu%lu",
+       "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu"
+};
+
+#endif
+
+static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
 {
-       switch (procnetdev_vsn) {
-       case 3:
-               sscanf(bp,
-                          "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
-                          &ife->stats.rx_bytes,
-                          &ife->stats.rx_packets,
-                          &ife->stats.rx_errors,
-                          &ife->stats.rx_dropped,
-                          &ife->stats.rx_fifo_errors,
-                          &ife->stats.rx_frame_errors,
-                          &ife->stats.rx_compressed,
-                          &ife->stats.rx_multicast,
-                          &ife->stats.tx_bytes,
-                          &ife->stats.tx_packets,
-                          &ife->stats.tx_errors,
-                          &ife->stats.tx_dropped,
-                          &ife->stats.tx_fifo_errors,
-                          &ife->stats.collisions,
-                          &ife->stats.tx_carrier_errors, &ife->stats.tx_compressed);
-               break;
-       case 2:
-               sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
-                          &ife->stats.rx_bytes,
-                          &ife->stats.rx_packets,
-                          &ife->stats.rx_errors,
-                          &ife->stats.rx_dropped,
-                          &ife->stats.rx_fifo_errors,
-                          &ife->stats.rx_frame_errors,
-                          &ife->stats.tx_bytes,
-                          &ife->stats.tx_packets,
-                          &ife->stats.tx_errors,
-                          &ife->stats.tx_dropped,
-                          &ife->stats.tx_fifo_errors,
-                          &ife->stats.collisions, &ife->stats.tx_carrier_errors);
-               ife->stats.rx_multicast = 0;
-               break;
-       case 1:
-               sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
-                          &ife->stats.rx_packets,
-                          &ife->stats.rx_errors,
-                          &ife->stats.rx_dropped,
-                          &ife->stats.rx_fifo_errors,
-                          &ife->stats.rx_frame_errors,
-                          &ife->stats.tx_packets,
-                          &ife->stats.tx_errors,
-                          &ife->stats.tx_dropped,
-                          &ife->stats.tx_fifo_errors,
-                          &ife->stats.collisions, &ife->stats.tx_carrier_errors);
-               ife->stats.rx_bytes = 0;
-               ife->stats.tx_bytes = 0;
+       memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
+
+       sscanf(bp, ss_fmt[procnetdev_vsn],
+                  &ife->stats.rx_bytes, /* missing for 0 */
+                  &ife->stats.rx_packets,
+                  &ife->stats.rx_errors,
+                  &ife->stats.rx_dropped,
+                  &ife->stats.rx_fifo_errors,
+                  &ife->stats.rx_frame_errors,
+                  &ife->stats.rx_compressed, /* missing for <= 1 */
+                  &ife->stats.rx_multicast, /* missing for <= 1 */
+                  &ife->stats.tx_bytes, /* missing for 0 */
+                  &ife->stats.tx_packets,
+                  &ife->stats.tx_errors,
+                  &ife->stats.tx_dropped,
+                  &ife->stats.tx_fifo_errors,
+                  &ife->stats.collisions,
+                  &ife->stats.tx_carrier_errors,
+                  &ife->stats.tx_compressed /* missing for <= 1 */
+                  );
+
+       if (procnetdev_vsn <= 1) {
+               if (procnetdev_vsn == 0) {
+                       ife->stats.rx_bytes = 0;
+                       ife->stats.tx_bytes = 0;
+               }
                ife->stats.rx_multicast = 0;
-               break;
+               ife->stats.rx_compressed = 0;
+               ife->stats.tx_compressed = 0;
        }
-       return 0;
 }
 
 static inline int procnetdev_version(char *buf)
 {
        if (strstr(buf, "compressed"))
-               return 3;
-       if (strstr(buf, "bytes"))
                return 2;
-       return 1;
+       if (strstr(buf, "bytes"))
+               return 1;
+       return 0;
 }
 
 static int if_readlist_proc(char *target)
@@ -1097,7 +1097,7 @@ static int if_readlist_proc(char *target)
        FILE *fh;
        char buf[512];
        struct interface *ife;
-       int err;
+       int err, procnetdev_vsn;
 
        if (proc_read)
                return 0;
@@ -1106,42 +1106,21 @@ static int if_readlist_proc(char *target)
 
        fh = fopen(_PATH_PROCNET_DEV, "r");
        if (!fh) {
-               perror_msg(_("Warning: cannot open %s (%s). Limited output.\n"), _PATH_PROCNET_DEV);
+               bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
                return if_readconf();
        }
        fgets(buf, sizeof buf, fh);     /* eat line */
        fgets(buf, sizeof buf, fh);
 
-#if 0                                  /* pretty, but can't cope with missing fields */
-       fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh, "face", "",        /* parsed separately */
-                                          "bytes", "%lu",
-                                          "packets", "%lu",
-                                          "errs", "%lu",
-                                          "drop", "%lu",
-                                          "fifo", "%lu",
-                                          "frame", "%lu",
-                                          "compressed", "%lu",
-                                          "multicast", "%lu",
-                                          "bytes", "%lu",
-                                          "packets", "%lu",
-                                          "errs", "%lu",
-                                          "drop", "%lu",
-                                          "fifo", "%lu",
-                                          "colls", "%lu",
-                                          "carrier", "%lu", "compressed", "%lu", NULL);
-       if (!fmt)
-               return -1;
-#else
        procnetdev_vsn = procnetdev_version(buf);
-#endif
 
        err = 0;
        while (fgets(buf, sizeof buf, fh)) {
-               char *s, name[IFNAMSIZ];
+               char *s, name[128];
 
                s = get_name(name, buf);
                ife = add_interface(name);
-               get_dev_fields(s, ife);
+               get_dev_fields(s, ife, procnetdev_vsn);
                ife->statistics_valid = 1;
                if (target && !strcmp(target, name))
                        break;
@@ -1151,9 +1130,6 @@ static int if_readlist_proc(char *target)
                err = -1;
                proc_read = 0;
        }
-#if 0
-       free(fmt);
-#endif
        fclose(fh);
        return err;
 }
@@ -1366,7 +1342,7 @@ static int do_if_fetch(struct interface *ife)
                } else {
                        errmsg = strerror(errno);
                }
-               error_msg(_("%s: error fetching interface information: %s\n"),
+               bb_error_msg(_("%s: error fetching interface information: %s\n"),
                                ife->name, errmsg);
                return -1;
        }
@@ -1397,7 +1373,12 @@ static struct hwtype loop_hwtype = {
 
 #if HAVE_HWETHER
 #include <net/if_arp.h>
+
+#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
+#include <net/ethernet.h>
+#else
 #include <linux/if_ether.h>
+#endif
 
 /* Display an Ethernet address in readable format. */
 static char *pr_ether(unsigned char *ptr)
@@ -1436,7 +1417,7 @@ static int in_ether(char *bufp, struct sockaddr *sap)
                        val = c - 'A' + 10;
                else {
 #ifdef DEBUG
-                       error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
+                       bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
 #endif
                        errno = EINVAL;
                        return (-1);
@@ -1453,7 +1434,7 @@ static int in_ether(char *bufp, struct sockaddr *sap)
                        val >>= 4;
                else {
 #ifdef DEBUG
-                       error_msg(_("in_ether(%s): invalid ether address!"), orig);
+                       bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
 #endif
                        errno = EINVAL;
                        return (-1);
@@ -1467,7 +1448,7 @@ static int in_ether(char *bufp, struct sockaddr *sap)
                if (*bufp == ':') {
 #ifdef DEBUG
                        if (i == ETH_ALEN) {
-                               error_msg(_("in_ether(%s): trailing : ignored!"), orig);
+                               bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
                        }
 #endif
                        bufp++;
@@ -1477,11 +1458,11 @@ static int in_ether(char *bufp, struct sockaddr *sap)
 #ifdef DEBUG
        /* That's it.  Any trailing junk? */
        if ((i == ETH_ALEN) && (*bufp != '\0')) {
-               error_msg(_("in_ether(%s): trailing junk!"), orig);
+               bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
                errno = EINVAL;
                return (-1);
        }
-       error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
+       bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
 #endif
 
        return (0);
@@ -1506,7 +1487,7 @@ static struct hwtype ether_hwtype = {
 /* Start the PPP encapsulation on the file descriptor. */
 static int do_ppp(int fd)
 {
-       error_msg(_("You cannot start PPP with this program."));
+       bb_error_msg(_("You cannot start PPP with this program."));
        return -1;
 }
 #endif                                                 /* KEEP_UNUSED */
@@ -1668,7 +1649,8 @@ static void hwinit()
 #endif                                                 /* KEEP_UNUSED */
 
 #ifdef IFF_PORTSEL
-static const char *if_port_text[][4] = {
+#if 0
+static const char * const if_port_text[][4] = {
        /* Keep in step with <linux/netdevice.h> */
        {"unknown", NULL, NULL, NULL},
        {"10base2", "bnc", "coax", NULL},
@@ -1679,6 +1661,19 @@ static const char *if_port_text[][4] = {
        {"100baseFX", NULL, NULL, NULL},
        {NULL, NULL, NULL, NULL},
 };
+#else
+static const char * const if_port_text[] = {
+       /* Keep in step with <linux/netdevice.h> */
+       "unknown",
+       "10base2",
+       "10baseT",
+       "AUI",
+       "100baseT",
+       "100baseTX",
+       "100baseFX",
+       NULL
+};
+#endif
 #endif
 
 /* Check our hardware type table for this type. */
@@ -1712,29 +1707,83 @@ static int hw_null_address(struct hwtype *hw, void *ap)
        return 1;
 }
 
-static const char TRext[] = "\0\0k\0M";
+#warning devel code
+static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
 
 static void print_bytes_scaled(unsigned long long ull, const char *end)
 {
        unsigned long long int_part;
-       unsigned long frac_part;
        const char *ext;
+       unsigned int frac_part;
        int i;
 
        frac_part = 0;
        ext = TRext;
        int_part = ull;
-       for (i = 0; i < 2; i++) {
+       i = 4;
+       do {
+#if 0
+               /* This does correct rounding and is a little larger.  But it
+                * uses KiB as the smallest displayed unit. */
+               if ((int_part < (1024*1024 - 51)) || !--i) {
+                       i = 0;
+                       int_part += 51;         /* 1024*.05 = 51.2 */
+                       frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
+               }
+               int_part /= 1024;
+               ext += 3;       /* KiB, MiB, GiB, TiB */
+#else
                if (int_part >= 1024) {
-                       frac_part = ((int_part % 1024) * 10) / 1024;
+                       frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
                        int_part /= 1024;
-                       ext += 2;       /* Kb, Mb */
+                       ext += 3;       /* KiB, MiB, GiB, TiB */
                }
-       }
+               --i;
+#endif
+       } while (i);
 
-       printf("X bytes:%Lu (%Lu.%lu %siB)%s", ull, int_part, frac_part, ext, end);
+       printf("X bytes:%Lu (%Lu.%u %sB)%s", ull, int_part, frac_part, ext, end);
 }
 
+static const char * const ife_print_flags_strs[] = {
+       "UP ",
+       "BROADCAST ",
+       "DEBUG ",
+       "LOOPBACK ",
+       "POINTOPOINT ",
+       "NOTRAILERS ",
+       "RUNNING ",
+       "NOARP ",
+       "PROMISC ",
+       "ALLMULTI ",
+       "SLAVE ",
+       "MASTER ",
+       "MULTICAST ",
+#ifdef HAVE_DYNAMIC
+       "DYNAMIC "
+#endif
+};
+
+static const unsigned short ife_print_flags_mask[] = {
+       IFF_UP,
+       IFF_BROADCAST,
+       IFF_DEBUG,
+       IFF_LOOPBACK,
+       IFF_POINTOPOINT,
+       IFF_NOTRAILERS,
+       IFF_RUNNING,
+       IFF_NOARP,
+       IFF_PROMISC,
+       IFF_ALLMULTI,
+       IFF_SLAVE,
+       IFF_MASTER,
+       IFF_MULTICAST,
+#ifdef HAVE_DYNAMIC
+       IFF_DYNAMIC
+#endif
+       0
+};
+
 static void ife_print(struct interface *ptr)
 {
        struct aftype *ap;
@@ -1780,7 +1829,7 @@ static void ife_print(struct interface *ptr)
                printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
 #ifdef IFF_PORTSEL
        if (ptr->flags & IFF_PORTSEL) {
-               printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
+               printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
                if (ptr->flags & IFF_AUTOMEDIA)
                        printf(_("(auto)"));
        }
@@ -1905,38 +1954,18 @@ static void ife_print(struct interface *ptr)
 
        printf("          ");
        /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
-       if (ptr->flags == 0)
+
+       if (ptr->flags == 0) {
                printf(_("[NO FLAGS] "));
-       if (ptr->flags & IFF_UP)
-               printf(_("UP "));
-       if (ptr->flags & IFF_BROADCAST)
-               printf(_("BROADCAST "));
-       if (ptr->flags & IFF_DEBUG)
-               printf(_("DEBUG "));
-       if (ptr->flags & IFF_LOOPBACK)
-               printf(_("LOOPBACK "));
-       if (ptr->flags & IFF_POINTOPOINT)
-               printf(_("POINTOPOINT "));
-       if (ptr->flags & IFF_NOTRAILERS)
-               printf(_("NOTRAILERS "));
-       if (ptr->flags & IFF_RUNNING)
-               printf(_("RUNNING "));
-       if (ptr->flags & IFF_NOARP)
-               printf(_("NOARP "));
-       if (ptr->flags & IFF_PROMISC)
-               printf(_("PROMISC "));
-       if (ptr->flags & IFF_ALLMULTI)
-               printf(_("ALLMULTI "));
-       if (ptr->flags & IFF_SLAVE)
-               printf(_("SLAVE "));
-       if (ptr->flags & IFF_MASTER)
-               printf(_("MASTER "));
-       if (ptr->flags & IFF_MULTICAST)
-               printf(_("MULTICAST "));
-#ifdef HAVE_DYNAMIC
-       if (ptr->flags & IFF_DYNAMIC)
-               printf(_("DYNAMIC "));
-#endif
+       } else {
+               int i = 0;
+               do {
+                       if (ptr->flags & ife_print_flags_mask[i]) {
+                               printf(_(ife_print_flags_strs[i]));
+                       }
+               } while (ife_print_flags_mask[++i]);
+       }
+
        /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
        printf(_(" MTU:%d  Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
 #ifdef SIOCSKEEPALIVE
@@ -1954,8 +1983,7 @@ static void ife_print(struct interface *ptr)
                 */
                printf("          ");
 
-               printf(_
-                          ("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
+               printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
                           ptr->stats.rx_packets, ptr->stats.rx_errors,
                           ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
                           ptr->stats.rx_frame_errors);
@@ -1963,8 +1991,7 @@ static void ife_print(struct interface *ptr)
                        printf(_("             compressed:%lu\n"),
                                   ptr->stats.rx_compressed);
                printf("          ");
-               printf(_
-                          ("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
+               printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
                           ptr->stats.tx_packets, ptr->stats.tx_errors,
                           ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
                           ptr->stats.tx_carrier_errors);
@@ -2047,7 +2074,7 @@ int display_interfaces(char *ifname)
 
        /* Create a channel to the NET kernel. */
        if ((skfd = sockets_open(0)) < 0) {
-               perror_msg_and_die("socket");
+               bb_perror_msg_and_die("socket");
        }
 
        /* Do we have to show the current setup? */