Print 2.1 interface aliases in netstat and ifconfig.
authorKlaas Freitag <freitag@suse.de>
Fri, 23 Oct 1998 06:15:04 +0000 (06:15 +0000)
committerKlaas Freitag <freitag@suse.de>
Fri, 23 Oct 1998 06:15:04 +0000 (06:15 +0000)
14 files changed:
Makefile
ifconfig.c
interface.c
interface.h
lib/Makefile
lib/inet_gr.c
lib/proc.c
lib/proc.h
lib/util.c [new file with mode: 0644]
lib/util.h [new file with mode: 0644]
man/en_US/ifconfig.8
man/en_US/netstat.8
netstat.c
statistics.c

index 260489d..3889dc2 100644 (file)
--- a/Makefile
+++ b/Makefile
 #              Extensively modified from 01/21/94 onwards by
 #              Alan Cox <A.Cox@swansea.ac.uk>
 #              Copyright 1993-1994 Swansea University Computer Society
-#              
+#
+# Be careful! 
+# This Makefile doesn't describe complete dependencies for all include files.
+# If you change include files you might need to do make clean. 
 #
 #      {1.20}  Bernd Eckenfels:        Even more modifications for the new 
 #                                      package layout
index 76a67c6..369e6e2 100644 (file)
@@ -15,6 +15,7 @@
  *             your option) any later version.
  * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *                     - gettext instead of catgets for i18n
+ *         10/1998  - Andi Kleen. Use interface list primitives.       
  */
 
 #include "config.h"
@@ -179,6 +180,8 @@ ife_print(struct interface *ptr)
     printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
 #if HAVE_AFINET6
   }
+  /* FIXME: should be integrated into interface.c.   */ 
+
   if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
     while(fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
@@ -264,6 +267,12 @@ ife_print(struct interface *ptr)
         ptr->mtu, ptr->metric?ptr->metric:1);
 
   /* If needed, display the interface statistics. */
+
+  if (ptr->statistics_valid) { 
+         /* XXX: statistics are currently only printed for the original address,
+          *      not for the aliases, although strictly speaking they're shared
+          *      by all addresses.
+          */
   printf("          ");
 
   printf(_("RX packets:%lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
@@ -284,7 +293,8 @@ ife_print(struct interface *ptr)
     printf(_("compressed:%lu "), ptr->stats.tx_compressed);
   if (ptr->tx_queue_len != -1)
     printf(_("txqueuelen:%d "), ptr->tx_queue_len);
-  printf("\n");
+  printf("\n"); 
+  }
 
   if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma || 
                ptr->map.base_addr)) {
@@ -305,40 +315,37 @@ ife_print(struct interface *ptr)
   printf("\n");
 }
 
-static void
-if_print(char *ifname)
+static int do_if_print(struct interface *ife, void *cookie)
 {
-  struct interface ife;
-
-  if (ifname == (char *)NULL) {
-    FILE *fd = fopen(_PATH_PROCNET_DEV, "r");
-    char buffer[256];
-    fgets(buffer, 256, fd);    /* chuck first two lines */
-    fgets(buffer, 256, fd);
-    while (!feof(fd)) {
-      char *name = buffer;
-      char *sep;
-      if (fgets(buffer, 256, fd) == NULL)
-       break;
-      sep = strrchr(buffer, ':');
-      if (sep)
-       *sep = 0;
-      while (*name == ' ') name++;
-      if (if_fetch(name, &ife) < 0) {
-       fprintf (stderr, _("%s: unknown interface.\n"), name);
-       continue;
-      }
-      
-      if (((ife.flags & IFF_UP) == 0) && !opt_a) continue;
-      ife_print(&ife);
-    }
-    fclose(fd);
-  } else {
-    if (if_fetch(ifname, &ife) < 0)
-      fprintf(stderr, _("%s: unknown interface.\n"), ifname);
-    else 
-      ife_print(&ife);
-  }
+    int *opt_a = (int *)cookie; 
+
+    if (if_fetch(ife->name, ife) < 0) {
+       fprintf (stderr, _("%s: error fetching interface information: %s\n\n"), 
+                ife->name, strerror(errno));
+       return -1;
+    }
+    if (!(ife->flags & IFF_UP) && !(*opt_a))
+       return 0;
+    ife_print(ife); 
+    return 0;
+}
+
+static void if_print(char *ifname)
+{
+    struct interface *ife;
+
+    if (!ifname) { 
+       for_all_interfaces(do_if_print, &opt_a); 
+    } else {
+       ife = lookup_interface(ifname); 
+       if (!ife)
+           fprintf(stderr, _("%s: interface not found.\n"), ifname); 
+       else if (if_fetch(ifname, ife) < 0)
+           fprintf(stderr, _("%s: error fetching interface information: %s"),
+                   ifname, strerror(errno)); 
+       else 
+           ife_print(ife);
+    }
 }
 
 
index 368c108..b32e6c9 100644 (file)
@@ -1,5 +1,9 @@
 /* Code to manipulate interface information, shared between ifconfig and
-   netstat. */
+   netstat. 
+
+   10/1998 partly rewriten by Andi Kleen to support interface list.   
+                  I don't claim that the list operations are efficient @).  
+*/
 
 #include "config.h"
 
 #include "net-support.h"
 #include "pathnames.h"
 #include "version.h"
+#include "proc.h"
 
 #include "interface.h"
 #include "sockets.h"
+#include "util.h"
+#include "intl.h"
+
+int procnetdev_vsn = 1; 
 
-int procnetdev_vsn = 1;
+static struct interface *int_list;
 
-static void 
-if_getstats(char *ifname, struct interface *ife)
+void add_interface(struct interface *n)
 {
-  FILE *f = fopen(_PATH_PROCNET_DEV, "r");
-  char buf[256];
-  char *bp;
+       struct interface *ife, **pp;
 
-  if (f == NULL)
-    return;
+       pp = &int_list;
+       for (ife = int_list; ife; pp = &ife->next, ife = ife->next) { 
+               /* XXX: should use numerical sort */ 
+               if (strcmp(ife->name, n->name) > 0) 
+                       break; 
+       }
+       n->next = (*pp);
+       (*pp) = n;  
+} 
 
-  fgets(buf, 255, f);  /* throw away first line of header */
-  fgets(buf, 255, f);
+struct interface *lookup_interface(char *name) 
+{ 
+       struct interface *ife;
+       if (!int_list && (if_readlist()) < 0)
+               return NULL;
+       for (ife = int_list; ife; ife = ife->next) {  
+               if (!strcmp(ife->name,name))
+                       break; 
+       }
+       return ife; 
+}
 
-  if (strstr(buf, "compressed")) 
-    procnetdev_vsn = 3;
-  else
-    if (strstr(buf, "bytes"))
-      procnetdev_vsn = 2;
-  
-  while (fgets(buf, 255, f)) {
-    bp=buf;
-    while(*bp && isspace(*bp))
-      bp++;
-    if (strncmp(bp, ifname, strlen(ifname)) == 0 && 
-       bp[strlen(ifname)] == ':') {
-      bp = strchr(bp, ':');
-      bp++;
-      switch (procnetdev_vsn) {
-      case 3:
-       sscanf(bp, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
-              &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, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
-              &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, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
-              &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;
-       ife->stats.rx_multicast = 0;
-       break;
-      }
-      break;
-    }
-  }
-  fclose(f);
+int 
+for_all_interfaces(int (*doit)(struct interface *, void *), void *cookie)
+{   
+       struct interface *ife;
+
+       if (!int_list && (if_readlist() < 0))
+               return -1;
+       for (ife = int_list; ife; ife = ife->next) { 
+               int err = doit(ife, cookie); 
+               if (err) 
+                       return err;
+       }
+       return 0;
+}
+
+static int if_readconf(void)
+{
+       int numreqs = 30;
+       struct ifconf ifc;
+       struct ifreq *ifr; 
+       int n, err = -1;  
+
+       int sk; 
+       sk = socket(PF_INET, SOCK_DGRAM, 0); 
+       if (sk < 0) { 
+               perror(_("error opening inet socket"));
+               return -1; 
+       }
+
+       ifc.ifc_buf = NULL;
+       for (;;) { 
+               ifc.ifc_len = sizeof(struct ifreq) * numreqs; 
+               ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); 
+               
+               if (ioctl(sk, SIOCGIFCONF, &ifc) < 0) { 
+                       perror("SIOCGIFCONF");
+                       goto out; 
+               }
+               
+               if (ifc.ifc_len == sizeof(struct ifreq)*numreqs) {
+                       /* assume it overflowed and try again */ 
+                       numreqs += 10; 
+                       continue;
+               }
+               break; 
+       }
+
+       for (ifr = ifc.ifc_req,n = 0; n < ifc.ifc_len; 
+                n += sizeof(struct ifreq), ifr++) {
+               struct interface *ife;
+               
+               ife = lookup_interface(ifr->ifr_name);
+               if (ife) 
+                       continue; 
+               
+               new(ife); 
+               strcpy(ife->name, ifr->ifr_name);
+               add_interface(ife); 
+       }
+       err = 0; 
+
+out:
+       free(ifc.ifc_buf);  
+       close(sk);
+       return err;  
+}
+
+static char *get_name(char *name, char *p)
+{
+       while (isspace(*p)) p++; 
+       while (*p) { 
+               if (isspace(*p)) 
+                       break; 
+               if (*p == ':') { /* could be an alias */ 
+                       char *dot = p, *dotname = name; 
+                       *name++ = *p++; 
+                       while (isdigit(*p))
+                               *name++ = *p++; 
+                       if (*p != ':') { /* it wasn't, backup */ 
+                               p = dot; 
+                               name = dotname; 
+                       } 
+                       if (*p == '\0') return NULL; 
+                       p++;
+                       break; 
+               }
+               *name++ = *p++; 
+       }
+       *name++ = '\0';
+       return p; 
+} 
+
+static int procnetdev_version(char *buf)
+{
+       if (strstr(buf,"compressed")) 
+               return 3;
+       if (strstr(buf,"bytes"))
+               return 2;
+       return 1; 
+}
+
+static int get_dev_fields(char *bp, struct interface *ife)
+ {
+        switch (procnetdev_vsn) {
+        case 3:
+                sscanf(bp, 
+                       "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+                                       &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, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+                                       &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, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+                                 &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;
+                  ife->stats.rx_multicast = 0;
+                  break;
+        }
+        return 0;
 }
 
+int if_readlist(void) 
+{
+       FILE *fh;
+       char buf[512];
+       struct interface *ife; 
+       int err;
+       
+       fh = fopen(_PATH_PROCNET_DEV,"r"); 
+       if (!fh) { 
+               perror(_PATH_PROCNET_DEV); 
+               return -1;
+       } 
+
+       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; 
+
+               new(ife); 
+       
+               s = get_name(ife->name, buf);    
+               get_dev_fields(s, ife);
+               ife->statistics_valid = 1;
+
+               add_interface(ife);
+       }
+       if (ferror(fh)) {
+               perror(_PATH_PROCNET_DEV); 
+               err = -1; 
+       } 
+       
+       if (!err) 
+               err = if_readconf();  
+
+#if 0
+       free(fmt); 
+#endif
+       return err; 
+} 
+
 /* Support for fetching an IPX address */
 
 #if HAVE_AFIPX
@@ -146,9 +320,6 @@ if_fetch(char *ifname, struct interface *ife)
 {
   struct ifreq ifr;
 
-  memset((char *) ife, 0, sizeof(struct interface));
-  strcpy(ife->name, ifname);
-
   strcpy(ifr.ifr_name, ifname);
   if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) return(-1);
   ife->flags = ifr.ifr_flags;
@@ -265,6 +436,5 @@ if_fetch(char *ifname, struct interface *ife)
   }
 #endif
 
-  if_getstats(ifname, ife);
   return 0;
 }
index 10e5365..937801d 100644 (file)
@@ -29,6 +29,8 @@ struct user_net_device_stats
 };
 
 struct interface {
+  struct interface *next;      
+
   char                 name[IFNAMSIZ];         /* interface name        */
   short                        type;                   /* if type               */
   short                        flags;                  /* various flags         */
@@ -55,15 +57,24 @@ struct interface {
   int                  has_ddp;
   int                  has_econet;
   char                 hwaddr[32];             /* HW address            */
+  int                  statistics_valid; 
   struct user_net_device_stats stats;          /* statistics            */
 };
 
-extern int procnetdev_vsn;
-
 extern int if_fetch(char *ifname, struct interface *ife);
 
-/* Check for supported features */
+extern int for_all_interfaces(int (*)(struct interface *, void *), void *); 
+extern struct interface *lookup_interface(char *name);
+extern int if_readlist(void);
 
-#if defined(SIOCSIFTXQLEN) && defined(ifr_qlen)
-#define HAVE_TXQUEUELEN
+/* Define for poor glibc2.0 users, the feature check is done at runtime */ 
+#if !defined(SIOCSIFTXQLEN)
+#define SIOCSIFTXQLEN      0x8943 
+#define SIOCGIFTXQLEN      0x8942 
 #endif
+
+#if !defined(ifr_qlen)
+#define ifr_qlen        ifr_ifru.ifru_ivalue
+#endif
+
+#define HAVE_TXQUEUELEN
index a8c0f93..55827d9 100644 (file)
@@ -21,7 +21,7 @@ AFOBJS         = unix.o inet.o inet6.o ax25.o ipx.o ddp.o ipx.o netrom.o af.o rose.o ec
 AFGROBJS = inet_gr.o inet6_gr.o ipx_gr.o ddp_gr.o netrom_gr.o ax25_gr.o rose_gr.o getroute.o
 AFSROBJS = inet_sr.o inet6_sr.o netrom_sr.o ipx_sr.o setroute.o
 ACTOBJS  = slip_ac.o ppp_ac.o activate.o
-VARIA   = getargs.o masq_info.o proc.o
+VARIA   = getargs.o masq_info.o proc.o util.o
 NLSMISC  = net-string.o
 
 OBJS   = $(NLSMISC) $(VARIA) $(AFOBJS) $(HWOBJS) \
index 308c445..5de96ef 100644 (file)
@@ -62,7 +62,7 @@ int rprint_fib(int ext, int numeric)
   window=0;
   mss=0;
 
-  fmt = proc_gen_fmt(_PATH_PROCNET_ROUTE, fp,
+  fmt = proc_gen_fmt(_PATH_PROCNET_ROUTE, 0, fp,
                                         "Iface", "%16s",
                                         "Destination", "%128s",
                                         "Gateway", "%128s",
@@ -181,7 +181,7 @@ int rprint_cache(int ext, int numeric)
                 "Flags Metric Ref    Use Iface    "
                 "MSS   Window irtt   HH  Arp\n"));
 
-  fmt = proc_gen_fmt(_PATH_PROCNET_ROUTE, fp,
+  fmt = proc_gen_fmt(_PATH_PROCNET_ROUTE, 0, fp,
                                         "Iface", "%16s",
                                         "Destination", "%128s",
                                         "Gateway", "%128s",
index 9e439f3..482deb0 100644 (file)
@@ -3,34 +3,41 @@
 #include <string.h> 
 #include <stdarg.h>
 #include <stdio.h>
+#include <ctype.h>
 
 /* Caller must free return string. */ 
+
 char * 
-proc_gen_fmt(char *name, FILE *fh, ...)
+proc_gen_fmt(char *name, int more, FILE *fh, ...)
 {
        char buf[512], format[512] = ""; 
-       char *title, *head; 
+       char *title, *head, *hdr
        va_list ap;
 
-       if (!fgets(buf, sizeof buf, fh)) 
+       if (!fgets(buf, (sizeof buf)-1, fh)) 
                return NULL; 
+       strcat(buf," ");  
 
        va_start(ap,fh); 
-       head = strtok(buf, " \t"); 
        title = va_arg(ap, char *); 
-       while (title && head) { 
+       for (hdr = buf; hdr; ) { 
+               while (isspace(*hdr) || *hdr == '|') hdr++; 
+               head = hdr; 
+               hdr = strpbrk(hdr,"| \t\n"); 
+               if (hdr) *hdr++ = 0; 
+
                if (!strcmp(title, head)) { 
                        strcat(format, va_arg(ap, char *)); 
                        title = va_arg(ap, char *); 
+                       if (!title || !head) break;
                } else {
-                       strcat(format, "%*[^ \t]"); 
+                       strcat(format, "%*s"); /* XXX */ 
                }
                strcat(format, " "); 
-               head = strtok(NULL, " \t"); 
        }
        va_end(ap); 
 
-       if (title) { 
+       if (!more && title) { 
                fprintf(stderr, "warning: %s does not contain required field %s\n",
                                                name, title); 
                return NULL; 
index 795765a..1139d5c 100644 (file)
@@ -1,4 +1,4 @@
 
 
 /* Generate a suitable scanf format for a column title line */ 
-char *proc_gen_fmt(char *name, FILE *fh, ...); 
+char *proc_gen_fmt(char *name, int more, FILE *fh, ...); 
diff --git a/lib/util.c b/lib/util.c
new file mode 100644 (file)
index 0000000..7d99971
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "util.h"
+
+static void oom(void)
+{ 
+       fprintf(stderr, "out of virtual memory\n");
+       exit(2); 
+}
+
+void *xmalloc(size_t sz)
+{
+       void *p = calloc(sz,1); 
+       if (!p) 
+               oom();
+       return p;
+}
+
+void *xrealloc(void *oldp, size_t sz)
+{
+       void *p = realloc(oldp,sz);
+       if (!p) 
+               oom();
+       return p;
+}
diff --git a/lib/util.h b/lib/util.h
new file mode 100644 (file)
index 0000000..cdb6aef
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stddef.h>
+
+void *xmalloc(size_t sz); 
+void *xrealloc(void *p, size_t sz);  
+
+#define new(p) ((p) = xmalloc(sizeof(*(p))))
index 72876ac..8c5c630 100644 (file)
@@ -167,22 +167,31 @@ Set the length of the transmit queue of the device. It is useful to set this
 to small values for slower devices with a high latency (modem links, ISDN)
 to prevent fast bulk transfers from disturbing interactive traffic like
 telnet too much. 
+.SH NOTES
+Since kernel release 2.2 there are no explicit interface statistics for
+alias interfaces anymore. The statistics printed for the original address
+are shared with all alias addresses on the same device. If you want per-address
+statistics you should add explicit accounting
+rules for the address using the 
+.BR ipchains(8)
+command.
+
 .SH FILES
 .I /proc/net/socket 
 .br
 .I /proc/net/dev
 .br
 .I /proc/net/if_inet6
-.br
-.I /etc/init.d/network
 .SH BUGS
 While appletalk DDP and IPX addresses will be displayed they cannot be
 altered by this command.
 .SH SEE ALSO
-route(8), netstat(8), arp(8), rarp(8)
+route(8), netstat(8), arp(8), rarp(8), ipchains(8)
 .SH AUTHORS
 Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
 .br
 Alan Cox, <Alan.Cox@linux.org>
 .br
 Phil Blundell, <Philip.Blundell@pobox.com>
+.br
+Andi Kleen, <ak@muc.de> 
index a43ff59..a1cbf4d 100644 (file)
@@ -4,6 +4,7 @@
 .\" Original: (mdw@tc.cornell.edu & dc6iq@insu1.etec.uni-karlsruhe.de)
 .\"
 .\" Modified: Bernd.Eckenfels@inka.de
+.\" Modified: Andi Kleen ak@muc.de 
 .\"
 .\"
 .TH NETSTAT 8 "20 Feb 1999" "net-tools" "Linux Programmer's Manual"
@@ -212,7 +213,7 @@ The socket is actively attempting to establish a connection.
 .TP
 .I
 SYN_RECV
-The connection is being initialized.
+A connection request has been received from the network.
 .TP
 .I
 FIN_WAIT1
@@ -225,7 +226,7 @@ remote end.
 .TP
 .I
 TIME_WAIT
-The socket is waiting after close for remote shutdown retransmission.
+The socket is waiting after close to handle packets still in the network.
 .TP
 .I
 CLOSED
@@ -371,6 +372,13 @@ to the socket.
 (this needs to be done by somebody who knows it)
 
 .PP
+.SH NOTES
+Since kernel release 2.2 netstat -i does not display interface statistics for
+alias interfaces anymore. To get per alias interface counters you need to
+setup explicit rules using the 
+.BR ipchains(8) 
+command.  
+
 .SH FILES
 .ta
 .I /etc/services
@@ -431,6 +439,7 @@ to the socket.
 .BR ipfw (4), 
 .BR ipfw (8), 
 .BR ipfwadm (8)
+.BR ipchains (8)
 
 .PP
 .SH BUGS
index b472379..c19b7ee 100644 (file)
--- a/netstat.c
+++ b/netstat.c
@@ -1,3 +1,4 @@
+
 /*
  * netstat     This file contains an implementation of the command
  *             that helps in debugging the networking modules.
@@ -44,6 +45,7 @@
  *                                     minor header file misplacement tidy up.
  *980411 {1.34} Arnaldo Carvalho        i18n: catgets -> gnu gettext, substitution
  *                                     of sprintf for snprintf
+ *10/1998              Andi Kleen              Use new interface primitives.
  *
  *             This program is free software; you can redistribute it
  *             and/or  modify it under  the terms of  the GNU General
@@ -1066,15 +1068,19 @@ static int ipx_info(void)
 static void
 ife_print(struct interface *ptr)
 {
-  printf("%-5.5s ", ptr->name);
+  printf("%-7.7s ", ptr->name);
   printf("%5d %3d ", ptr->mtu, ptr->metric);
   /* If needed, display the interface statistics. */
-  printf("%6lu %6lu %6lu %6lu ",
-        ptr->stats.rx_packets, ptr->stats.rx_errors,
-        ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
-  printf("%6lu %6lu %6lu %6lu ",
-        ptr->stats.tx_packets, ptr->stats.tx_errors,
-        ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
+  if (ptr->statistics_valid) {  
+         printf("%6lu %6lu %6lu %6lu ",
+                        ptr->stats.rx_packets, ptr->stats.rx_errors,
+                        ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
+         printf("%6lu %6lu %6lu %6lu ",
+                        ptr->stats.tx_packets, ptr->stats.tx_errors,
+                        ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
+  } else { 
+         printf("%-56s", "     - no statistics available -");  
+  } 
   if (ptr->flags == 0) printf(_("[NO FLAGS]"));
   if (ptr->flags & IFF_ALLMULTI) printf("A");
   if (ptr->flags & IFF_BROADCAST) printf("B");
@@ -1089,47 +1095,38 @@ ife_print(struct interface *ptr)
   printf("\n");
 }
 
+static int do_if_print(struct interface *ife, void *cookie)
+{
+    int *opt_a = (int *)cookie; 
+    if (if_fetch(ife->name, ife) < 0) {
+               fprintf (stderr, _("%s: unknown interface.\n"), ife->name);
+               return -1;
+    }
+    if (!(ife->flags & IFF_UP) && !(*opt_a))
+               return 0;
+    ife_print(ife); 
+       return 0;
+}
+
 static int
 iface_info(void)
 {
-  struct interface ife;
-  char buffer[256];
-  FILE *fd;
-  
-  printf(_("Kernel Interface table\n"));
-  printf(_("Iface   MTU Met  RX-OK RX-ERR RX-DRP RX-OVR  TX-OK TX-ERR TX-DRP TX-OVR Flags\n"));
-  
-  /* Create a channel to the NET kernel. */
   if ((skfd = sockets_open()) < 0) {
     perror("socket");
     exit(1);
   }
 
-  fd = fopen(_PATH_PROCNET_DEV, "r");
-  fgets(buffer, 256, fd);      /* chuck first two lines */
-  fgets(buffer, 256, fd);
-  while (!feof(fd)) {
-    char *name = buffer;
-    char *sep;
-    if (fgets(buffer, 256, fd) == NULL)
-      break;
-    sep = strrchr(buffer, ':');
-    if (sep)
-      *sep = 0;
-    while (*name == ' ') name++;
-    if (if_fetch(name, &ife) < 0) {
-      fprintf(stderr, _("%s: unknown interface.\n"),
-             name);
-      continue;
-    }
-    
-    if (((ife.flags & IFF_UP) == 0) && !flag_all) continue;
-    ife_print(&ife);
+  printf(_("Kernel Interface table\n"));
+  printf(_("Iface     MTU Met  RX-OK RX-ERR RX-DRP RX-OVR  TX-OK TX-ERR TX-DRP TX-OVR Flags\n"));
+  
+  if (for_all_interfaces(do_if_print, &flag_all) < 0) {
+         perror(_("missing interface information")); 
+         exit(1);
   }
 
-  fclose(fd);
   close(skfd);
-
+  skfd = -1;
+  
   return 0;
 }
 
index b02cae7..2c8ad1f 100644 (file)
@@ -25,6 +25,7 @@ struct entry {
        char *title;
        char *out; 
        enum State type;
+       unsigned long val; 
 }; 
 
 static enum State state;