Release 6
[unix-history] / usr / src / usr.bin / netstat / main.c
index e69f212..3ab8b74 100644 (file)
@@ -12,21 +12,28 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.27 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     5.31 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
-#include <sys/socket.h>
 #include <sys/file.h>
 #include <sys/file.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
 #include <errno.h>
 #include <errno.h>
+#include <kvm.h>
+#include <limits.h>
 #include <netdb.h>
 #include <nlist.h>
 #include <netdb.h>
 #include <nlist.h>
-#include <kvm.h>
+#include <paths.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdlib.h>
 #include <string.h>
-#include <paths.h>
+#include <unistd.h>
+#include "netstat.h"
 
 struct nlist nl[] = {
 #define        N_MBSTAT        0
 
 struct nlist nl[] = {
 #define        N_MBSTAT        0
@@ -81,6 +88,16 @@ struct nlist nl[] = {
        { "_nfile" },
 #define        N_FILE          25
        { "_file" },
        { "_nfile" },
 #define        N_FILE          25
        { "_file" },
+#define N_IGMPSTAT     26
+       { "_igmpstat" },
+#define N_MRTPROTO     27
+       { "_ip_mrtproto" },
+#define N_MRTSTAT      28
+       { "_mrtstat" },
+#define N_MRTTABLE     29
+       { "_mrttable" },
+#define N_VIFTABLE     30
+       { "_viftable" },
 
     /* BBN Internet protocol implementation */
 #define        N_TCP           23
 
     /* BBN Internet protocol implementation */
 #define        N_TCP           23
@@ -95,23 +112,12 @@ struct nlist nl[] = {
        "",
 };
 
        "",
 };
 
-/* internet protocols */
-extern int protopr(), bbnprotopr();
-extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
-/* ns protocols */
-extern int tcpstats(), udpstats(), ipstats(), icmpstats(), rdpstats();
-extern int nsprotopr();
-extern int spp_stats(), idp_stats(), nserr_stats();
-/* iso protocols */
-extern int iso_protopr();
-extern int tp_stats(), esis_stats(), clnp_stats(), cltp_stats();
-
 struct protox {
        u_char  pr_index;               /* index into nlist of cb head */
        u_char  pr_sindex;              /* index into nlist of stat block */
        u_char  pr_wanted;              /* 1 if wanted, 0 otherwise */
 struct protox {
        u_char  pr_index;               /* index into nlist of cb head */
        u_char  pr_sindex;              /* index into nlist of stat block */
        u_char  pr_wanted;              /* 1 if wanted, 0 otherwise */
-       int     (*pr_cblocks)();        /* control blocks printing routine */
-       int     (*pr_stats)();          /* statistics printing routine */
+       void    (*pr_cblocks)();        /* control blocks printing routine */
+       void    (*pr_stats)();          /* statistics printing routine */
        char    *pr_name;               /* well-known name */
 };
 
        char    *pr_name;               /* well-known name */
 };
 
@@ -171,27 +177,14 @@ struct protox isoprotox[] = {
 
 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
 
 
 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
 
-char   *nlistf;
-char   *memf;
-int    kmem;
-int    kflag;
-int    Aflag;
-int    aflag;
-int    hflag;
-int    iflag;
-int    mflag;
-int    nflag;
-int    pflag;
-int    rflag;
-int    sflag;
-int    tflag;
-int    dflag;
-int    interval;
-char   *interface;
-int    unit;
-
-int    af = AF_UNSPEC;
+static void printproto __P((struct protox *, char *));
+static void usage __P(());
+static struct protox *name2protox __P((char *));
+static struct protox *knownname __P((char *));
+
+kvm_t *kvmd;
 
 
+int
 main(argc, argv)
        int argc;
        char **argv;
 main(argc, argv)
        int argc;
        char **argv;
@@ -200,18 +193,28 @@ main(argc, argv)
        extern int optind;
        register struct protoent *p;
        register struct protox *tp;     /* for printing cblocks & stats */
        extern int optind;
        register struct protoent *p;
        register struct protox *tp;     /* for printing cblocks & stats */
-       struct protox *name2protox();   /* for -p */
+       register char *cp;
        int ch;
        int ch;
-       void usage(); 
+       char *nlistf = NULL, *memf = NULL;
+       char buf[_POSIX2_LINE_MAX];
+
+       if (cp = rindex(argv[0], '/'))
+               prog = cp + 1;
+       else
+               prog = argv[0];
+       af = AF_UNSPEC;
 
 
-       while ((ch = getopt(argc, argv, "Aadf:hI:iM:mN:np:rstuw")) != EOF)
-               switch((char)ch) {
+       while ((ch = getopt(argc, argv, "AaBdf:hI:iM:mN:np:rstuw:")) != EOF)
+               switch(ch) {
                case 'A':
                        Aflag = 1;
                        break;
                case 'a':
                        aflag = 1;
                        break;
                case 'A':
                        Aflag = 1;
                        break;
                case 'a':
                        aflag = 1;
                        break;
+               case 'B':
+                       Bflag = 1;
+                       break;
                case 'd':
                        dflag = 1;
                        break;
                case 'd':
                        dflag = 1;
                        break;
@@ -226,7 +229,8 @@ main(argc, argv)
                                af = AF_ISO;
                        else {
                                (void)fprintf(stderr,
                                af = AF_ISO;
                        else {
                                (void)fprintf(stderr,
-                                   "%s: unknown address family\n", optarg);
+                                   "%s: %s: unknown address family\n",
+                                   prog, optarg);
                                exit(1);
                        }
                        break;
                                exit(1);
                        }
                        break;
@@ -237,7 +241,8 @@ main(argc, argv)
                        char *cp;
 
                        iflag = 1;
                        char *cp;
 
                        iflag = 1;
-                       for (cp = interface = optarg; isalpha(*cp); cp++);
+                       for (cp = interface = optarg; isalpha(*cp); cp++)
+                               continue;
                        unit = atoi(cp);
                        *cp = '\0';
                        break;
                        unit = atoi(cp);
                        *cp = '\0';
                        break;
@@ -247,7 +252,6 @@ main(argc, argv)
                        break;
                case 'M':
                        memf = optarg;
                        break;
                case 'M':
                        memf = optarg;
-                       kflag = 1;
                        break;
                case 'm':
                        mflag = 1;
                        break;
                case 'm':
                        mflag = 1;
@@ -261,8 +265,8 @@ main(argc, argv)
                case 'p':
                        if ((tp = name2protox(optarg)) == NULL) {
                                (void)fprintf(stderr,
                case 'p':
                        if ((tp = name2protox(optarg)) == NULL) {
                                (void)fprintf(stderr,
-                                   "%s: unknown or uninstrumented protocol\n",
-                                   optarg);
+                                   "%s: %s: unknown or uninstrumented protocol\n",
+                                   prog, optarg);
                                exit(1);
                        }
                        pflag = 1;
                                exit(1);
                        }
                        pflag = 1;
@@ -271,7 +275,7 @@ main(argc, argv)
                        rflag = 1;
                        break;
                case 's':
                        rflag = 1;
                        break;
                case 's':
-                       sflag = 1;
+                       ++sflag;
                        break;
                case 't':
                        tflag = 1;
                        break;
                case 't':
                        tflag = 1;
@@ -301,13 +305,12 @@ main(argc, argv)
                }
                if (*argv) {
                        nlistf = *argv;
                }
                if (*argv) {
                        nlistf = *argv;
-                       if (*++argv) {
+                       if (*++argv)
                                memf = *argv;
                                memf = *argv;
-                               kflag = 1;
-                       }
                }
        }
 #endif
                }
        }
 #endif
+
        /*
         * Discard setgid privileges if not the running kernel so that bad
         * guys can't print interesting stuff from kernel memory.
        /*
         * Discard setgid privileges if not the running kernel so that bad
         * guys can't print interesting stuff from kernel memory.
@@ -315,16 +318,19 @@ main(argc, argv)
        if (nlistf != NULL || memf != NULL)
                setgid(getgid());
 
        if (nlistf != NULL || memf != NULL)
                setgid(getgid());
 
-       if (kvm_openfiles(nlistf, memf, NULL) == -1) {
-               fprintf(stderr, "netstat: kvm_openfiles: %s\n", kvm_geterr());
+       if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) {
+               fprintf(stderr, "%s: kvm_open: %s\n", prog, buf);
                exit(1);
        }
                exit(1);
        }
-       if (kvm_nlist(nl) < 0 || nl[0].n_type == 0) {
-               fprintf(stderr, "netstat: no namelist\n");
+       if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
+               if (nlistf)
+                       fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf);
+               else
+                       fprintf(stderr, "%s: no namelist\n", prog);
                exit(1);
        }
        if (mflag) {
                exit(1);
        }
        if (mflag) {
-               mbpr((off_t)nl[N_MBSTAT].n_value);
+               mbpr(nl[N_MBSTAT].n_value);
                exit(0);
        }
        if (pflag) {
                exit(0);
        }
        if (pflag) {
@@ -351,21 +357,22 @@ main(argc, argv)
        }
        if (rflag) {
                if (sflag)
        }
        if (rflag) {
                if (sflag)
-                       rt_stats((off_t)nl[N_RTSTAT].n_value);
+                       rt_stats(nl[N_RTSTAT].n_value);
                else
                else
-                       routepr((off_t)nl[N_RTREE].n_value);
+                       routepr(nl[N_RTREE].n_value);
+               exit(0);
+       }
+       if (Bflag) {
+               if (sflag)
+                       mrt_stats(nl[N_MRTPROTO].n_value,
+                           nl[N_MRTSTAT].n_value);
+               else
+                       mroutepr(nl[N_MRTPROTO].n_value,
+                           nl[N_MRTTABLE].n_value,
+                           nl[N_VIFTABLE].n_value);
                exit(0);
        }
                exit(0);
        }
-    if (af == AF_INET || af == AF_UNSPEC) {
-       struct protox *head;
-
-       head = (nl[N_TCB].n_type == 0) ? bbnprotox : berkprotox;
-       setprotoent(1);
-       setservent(1);
 
 
-       for (tp = head; tp->pr_name; tp++) {
-               if (tp->pr_wanted == 0)
-                       continue;
 
                if (sflag) {
                        if (tp->pr_stats)
 
                if (sflag) {
                        if (tp->pr_stats)
@@ -373,38 +380,27 @@ main(argc, argv)
                } else if (tp->pr_cblocks)
                        (*tp->pr_cblocks)(nl[tp->pr_index].n_value, tp->pr_name);
        }
                } else if (tp->pr_cblocks)
                        (*tp->pr_cblocks)(nl[tp->pr_index].n_value, tp->pr_name);
        }
-       endprotoent();
-    }
-    if (af == AF_NS || af == AF_UNSPEC) {
-       for (tp = nsprotox; tp->pr_name; tp++) {
-               if (sflag) {
-                       if (tp->pr_stats)
-                               (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
-                                       tp->pr_name);
-               } else
-                       if (tp->pr_cblocks)
-                               (*tp->pr_cblocks)(nl[tp->pr_index].n_value,
-                                       tp->pr_name);
-       }
-    }
-    if (af == AF_ISO || af == AF_UNSPEC) {
-       for (tp = isoprotox; tp->pr_name; tp++) {
-               if (sflag) {
-                       if (tp->pr_stats)
-                               (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
-                                       tp->pr_name);
-               } else
-                       if (tp->pr_cblocks)
-                               (*tp->pr_cblocks)(nl[tp->pr_index].n_value,
-                                       tp->pr_name);
+       if (pr != NULL && (off || af != AF_UNSPEC))
+               (*pr)(off, name);
+}
+
+/*
+ * Read kernel memory, return 0 on success.
+ */
+int
+kread(addr, buf, size)
+       u_long addr;
+       char *buf;
+       int size;
+{
+
+       if (kvm_read(kvmd, addr, buf, size) != size) {
+               /* XXX this duplicates kvm_read's error printout */
+               (void)fprintf(stderr, "%s: kvm_read %s\n", prog,
+                   kvm_geterr(kvmd));
+               return (-1);
        }
        }
-    }
-    if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
-           unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value,
-               (struct protosw *)nl[N_UNIXSW].n_value);
-    if (af == AF_UNSPEC && sflag)
-       impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value);
-    exit(0);
+       return (0);
 }
 
 char *
 }
 
 char *
@@ -414,26 +410,33 @@ plural(n)
        return (n != 1 ? "s" : "");
 }
 
        return (n != 1 ? "s" : "");
 }
 
+char *
+plurales(n)
+       int n;
+{
+       return (n != 1 ? "es" : "");
+}
+
 /*
  * Find the protox for the given "well-known" name.
  */
 /*
  * Find the protox for the given "well-known" name.
  */
-struct protox *
+static struct protox *
 knownname(name)
        char *name;
 {
        struct protox **tpp, *tp;
 
        for (tpp = protoprotox; *tpp; tpp++)
 knownname(name)
        char *name;
 {
        struct protox **tpp, *tp;
 
        for (tpp = protoprotox; *tpp; tpp++)
-           for (tp = *tpp; tp->pr_name; tp++)
-               if (strcmp(tp->pr_name, name) == 0)
-                       return(tp);
-       return(NULL);
+               for (tp = *tpp; tp->pr_name; tp++)
+                       if (strcmp(tp->pr_name, name) == 0)
+                               return (tp);
+       return (NULL);
 }
 
 /*
  * Find the protox corresponding to name.
  */
 }
 
 /*
  * Find the protox corresponding to name.
  */
-struct protox *
+static struct protox *
 name2protox(name)
        char *name;
 {
 name2protox(name)
        char *name;
 {
@@ -446,7 +449,7 @@ name2protox(name)
         * fails, check if name is an alias for an Internet protocol.
         */
        if (tp = knownname(name))
         * fails, check if name is an alias for an Internet protocol.
         */
        if (tp = knownname(name))
-               return(tp);
+               return (tp);
 
        setprotoent(1);                 /* make protocol lookup cheaper */
        while (p = getprotoent()) {
 
        setprotoent(1);                 /* make protocol lookup cheaper */
        while (p = getprotoent()) {
@@ -454,18 +457,18 @@ name2protox(name)
                for (alias = p->p_aliases; *alias; alias++)
                        if (strcmp(name, *alias) == 0) {
                                endprotoent();
                for (alias = p->p_aliases; *alias; alias++)
                        if (strcmp(name, *alias) == 0) {
                                endprotoent();
-                               return(knownname(p->p_name));
+                               return (knownname(p->p_name));
                        }
        }
        endprotoent();
                        }
        }
        endprotoent();
-       return(NULL);
+       return (NULL);
 }
 
 }
 
-void
+static void
 usage()
 {
        (void)fprintf(stderr,
 usage()
 {
        (void)fprintf(stderr,
-"usage: netstat [-Aan] [-f address_family] [-M core] [-N system]\n");
+"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
        (void)fprintf(stderr,
 "               [-himnrs] [-f address_family] [-M core] [-N system]\n");
        (void)fprintf(stderr,
        (void)fprintf(stderr,
 "               [-himnrs] [-f address_family] [-M core] [-N system]\n");
        (void)fprintf(stderr,