BSD 4_3_Reno release
[unix-history] / usr / src / usr.bin / netstat / main.c
index 6d3faee..eef7429 100644 (file)
@@ -1,16 +1,45 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * 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.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)main.c     4.10 84/03/12";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c     5.19 (Berkeley) 6/18/90";
+#endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/vmmac.h>
 
 #include <sys/param.h>
 #include <sys/vmmac.h>
+#include <sys/socket.h>
+#include <sys/file.h>
 #include <machine/pte.h>
 #include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <nlist.h>
 #include <stdio.h>
 #include <machine/pte.h>
 #include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <nlist.h>
 #include <stdio.h>
+#include <paths.h>
 
 
+#define nl netstatnl
 struct nlist nl[] = {
 #define        N_MBSTAT        0
        { "_mbstat" },
 struct nlist nl[] = {
 #define        N_MBSTAT        0
        { "_mbstat" },
@@ -32,8 +61,8 @@ struct nlist nl[] = {
        { "_Syssize" },
 #define        N_IFNET         9
        { "_ifnet" },
        { "_Syssize" },
 #define        N_IFNET         9
        { "_ifnet" },
-#define        N_HOSTS         10
-       { "_hosts" },
+#define        N_IMP           10
+       { "_imp_softc" },
 #define        N_RTHOST        11
        { "_rthost" },
 #define        N_RTNET         12
 #define        N_RTHOST        11
        { "_rthost" },
 #define        N_RTNET         12
@@ -42,12 +71,59 @@ struct nlist nl[] = {
        { "_icmpstat" },
 #define        N_RTSTAT        14
        { "_rtstat" },
        { "_icmpstat" },
 #define        N_RTSTAT        14
        { "_rtstat" },
+#define        N_NFILE         15
+       { "_nfile" },
+#define        N_FILE          16
+       { "_file" },
+#define        N_UNIXSW        17
+       { "_unixsw" },
+#define N_RTHASHSIZE   18
+       { "_rthashsize" },
+#define N_IDP          19
+       { "_nspcb"},
+#define N_IDPSTAT      20
+       { "_idpstat"},
+#define N_SPPSTAT      21
+       { "_spp_istat"},
+#define N_NSERR                22
+       { "_ns_errstat"},
+#define        N_CLNPSTAT      23
+       { "_clnp_stat"},
+#define        IN_TP           24
+       { "_tp_inpcb" },
+#define        ISO_TP          25
+       { "_tp_isopcb" },
+#define        ISO_X25         26
+       { /*"_x25_isopcb"*/ "_file"}, /* fast gross hack to speed up */
+#define        N_TPSTAT        27
+       { "_tp_stat" },
+#define        N_X25STAT       28
+       { /*"_x25_stat"*/ "_file"},
+#define        N_ESISSTAT      29
+       { "_esis_stat"},
+#define N_NIMP         30
+       { "_nimp"},
+#define N_RTREE                31
+       { "_radix_node_head"},
+#define N_CLTP         32
+       { "_cltb"},
+#define N_CLTPSTAT     33
+       { "_cltpstat"},
+
        "",
 };
 
        "",
 };
 
+/* internet protocols */
 extern int protopr();
 extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
 extern int protopr();
 extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
+/* ns protocols */
+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();
 
 
+#define NULLPROTOX     ((struct protox *) 0)
 struct protox {
        u_char  pr_index;               /* index into nlist of cb head */
        u_char  pr_sindex;              /* index into nlist of stat block */
 struct protox {
        u_char  pr_index;               /* index into nlist of cb head */
        u_char  pr_sindex;              /* index into nlist of stat block */
@@ -60,6 +136,8 @@ struct protox {
          tcp_stats,    "tcp" },
        { N_UDB,        N_UDPSTAT,      1,      protopr,
          udp_stats,    "udp" },
          tcp_stats,    "tcp" },
        { N_UDB,        N_UDPSTAT,      1,      protopr,
          udp_stats,    "udp" },
+       { IN_TP,        N_TPSTAT,       1,      protopr,
+         tp_stats,     "tpip" },
        { -1,           N_IPSTAT,       1,      0,
          ip_stats,     "ip" },
        { -1,           N_ICMPSTAT,     1,      0,
        { -1,           N_IPSTAT,       1,      0,
          ip_stats,     "ip" },
        { -1,           N_ICMPSTAT,     1,      0,
@@ -68,10 +146,40 @@ struct protox {
          0,            0 }
 };
 
          0,            0 }
 };
 
+struct protox nsprotox[] = {
+       { N_IDP,        N_IDPSTAT,      1,      nsprotopr,
+         idp_stats,    "idp" },
+       { N_IDP,        N_SPPSTAT,      1,      nsprotopr,
+         spp_stats,    "spp" },
+       { -1,           N_NSERR,        1,      0,
+         nserr_stats,  "ns_err" },
+       { -1,           -1,             0,      0,
+         0,            0 }
+};
+
+struct protox isoprotox[] = {
+       { ISO_TP,       N_TPSTAT,       1,      iso_protopr,
+         tp_stats,     "tp" },
+       { N_CLTP,       N_CLTPSTAT,     1,      iso_protopr,
+         cltp_stats,   "cltp" },
+#ifdef notdef
+       { ISO_X25,      N_X25STAT,      1,      x25_protopr,
+         x25_stats,    "x25" },
+#endif
+       { -1,           N_CLNPSTAT,     1,       0,
+         clnp_stats,   "clnp"},
+       { -1,           N_ESISSTAT,     1,       0,
+         esis_stats,   "esis"},
+       { -1,           -1,             0,      0,
+         0,            0 }
+};
+
+struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULLPROTOX };
+
 struct pte *Sysmap;
 
 struct pte *Sysmap;
 
-char   *system = "/vmunix";
-char   *kmemf = "/dev/kmem";
+char   *system = _PATH_UNIX;
+char   *kmemf;
 int    kmem;
 int    kflag;
 int    Aflag;
 int    kmem;
 int    kflag;
 int    Aflag;
@@ -80,110 +188,142 @@ int      hflag;
 int    iflag;
 int    mflag;
 int    nflag;
 int    iflag;
 int    mflag;
 int    nflag;
+int    pflag;
 int    rflag;
 int    sflag;
 int    tflag;
 int    rflag;
 int    sflag;
 int    tflag;
+int    dflag;
 int    interval;
 int    interval;
-char   usage[] = "[ -Aaihmnrst ] [ interval ] [ system ] [ core ]";
+char   *interface;
+int    unit;
+
+int    af = AF_UNSPEC;
+
+extern char *malloc();
+extern off_t lseek();
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
-       int i;
-       char *cp, *name;
+       extern char *optarg;
+       extern int optind;
        register struct protoent *p;
        register struct protoent *p;
+       register struct protox *tp;     /* for printing cblocks & stats */
+       struct protox *name2protox();   /* for -p */
+       int ch;
 
 
-       name = argv[0];
-       argc--, argv++;
-       while (argc > 0 && **argv == '-') {
-               for (cp = &argv[0][1]; *cp; cp++)
-               switch(*cp) {
-
+       while ((ch = getopt(argc, argv, "AI:af:himnp:drstu")) != EOF)
+               switch((char)ch) {
                case 'A':
                        Aflag++;
                        break;
                case 'A':
                        Aflag++;
                        break;
+               case 'I': {
+                       char *cp;
 
 
+                       iflag++;
+                       for (cp = interface = optarg; isalpha(*cp); cp++);
+                       unit = atoi(cp);
+                       *cp = '\0';
+                       break;
+               }
                case 'a':
                        aflag++;
                        break;
                case 'a':
                        aflag++;
                        break;
-
+               case 'd':
+                       dflag++;
+                       break;
+               case 'f':
+                       if (strcmp(optarg, "ns") == 0)
+                               af = AF_NS;
+                       else if (strcmp(optarg, "inet") == 0)
+                               af = AF_INET;
+                       else if (strcmp(optarg, "unix") == 0)
+                               af = AF_UNIX;
+                       else if (strcmp(optarg, "iso") == 0)
+                               af = AF_ISO;
+                       else {
+                               fprintf(stderr, "%s: unknown address family\n", optarg);
+                               exit(10);
+                       }
+                       break;
                case 'h':
                        hflag++;
                        break;
                case 'h':
                        hflag++;
                        break;
-
                case 'i':
                        iflag++;
                        break;
                case 'i':
                        iflag++;
                        break;
-
                case 'm':
                        mflag++;
                        break;
                case 'm':
                        mflag++;
                        break;
-
                case 'n':
                        nflag++;
                        break;
                case 'n':
                        nflag++;
                        break;
-
+               case 'p':
+                       if ((tp = name2protox(optarg)) == NULLPROTOX) {
+                               fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg);
+                               exit(10);
+                       }
+                       pflag++;
+                       break;
                case 'r':
                        rflag++;
                        break;
                case 'r':
                        rflag++;
                        break;
-
                case 's':
                        sflag++;
                        break;
                case 's':
                        sflag++;
                        break;
-
                case 't':
                        tflag++;
                        break;
                case 't':
                        tflag++;
                        break;
-
+               case 'u':
+                       af = AF_UNIX;
+                       break;
+               case '?':
                default:
                default:
-use:
-                       printf("usage: %s %s\n", name, usage);
-                       exit(1);
+                       usage();
                }
                }
-               argv++, argc--;
-       }
-       if (argc > 0 && isdigit(argv[0][0])) {
-               interval = atoi(argv[0]);
-               if (interval <= 0)
-                       goto use;
-               argv++, argc--;
-               iflag++;
-       }
+       argv += optind;
+       argc -= optind;
+
        if (argc > 0) {
        if (argc > 0) {
-               system = *argv;
-               argv++, argc--;
+               if (isdigit(argv[0][0])) {
+                       interval = atoi(argv[0]);
+                       if (interval <= 0)
+                               usage();
+                       argv++, argc--;
+                       iflag++;
+               }
+               if (argc > 0) {
+                       system = *argv;
+                       argv++, argc--;
+                       if (argc > 0) {
+                               kmemf = *argv;
+                               kflag++;
+                       }
+               }
        }
        }
-       nlist(system, nl);
-       if (nl[0].n_type == 0) {
-               fprintf(stderr, "%s: no namelist\n", system);
+       if (kvm_openfiles(system, kmemf, (char *)0) == -1) {
+               fprintf("netstat(kvm_openfiles): %s\n", kvm_geterr());
                exit(1);
        }
                exit(1);
        }
-       if (argc > 0) {
-               kmemf = *argv;
-               kflag++;
-       }
-       kmem = open(kmemf, 0);
-       if (kmem < 0) {
-               fprintf(stderr, "cannot open ");
-               perror(kmemf);
+       if (kvm_nlist(nl) < 0 || nl[0].n_type == 0) {
+               fprintf(stderr, "%s: no namelist\n", system);
                exit(1);
        }
                exit(1);
        }
-       if (kflag) {
-               off_t off;
-
-               off = nl[N_SYSMAP].n_value & 0x7fffffff;
-               lseek(kmem, off, 0);
-               nl[N_SYSSIZE].n_value *= 4;
-               Sysmap = (struct pte *)malloc(nl[N_SYSSIZE].n_value);
-               if (Sysmap == 0) {
-                       perror("Sysmap");
-                       exit(1);
-               }
-               read(kmem, Sysmap, nl[N_SYSSIZE].n_value);
-       }
        if (mflag) {
        if (mflag) {
-               mbpr(nl[N_MBSTAT].n_value);
+               mbpr((off_t)nl[N_MBSTAT].n_value);
+               exit(0);
+       }
+       if (pflag) {
+               if (tp->pr_stats)
+                       (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
+                               tp->pr_name);
+               else
+                       printf("%s: no stats routine\n", tp->pr_name);
+               exit(0);
+       }
+       if (hflag) {
+               hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value);
                exit(0);
        }
        /*
                exit(0);
        }
        /*
@@ -196,58 +336,127 @@ use:
                intpr(interval, nl[N_IFNET].n_value);
                exit(0);
        }
                intpr(interval, nl[N_IFNET].n_value);
                exit(0);
        }
-       if (hflag) {
-               hostpr(nl[N_HOSTS].n_value);
-               exit(0);
-       }
        if (rflag) {
                if (sflag)
        if (rflag) {
                if (sflag)
-                       rt_stats(nl[N_RTSTAT].n_value);
+                       rt_stats((off_t)nl[N_RTSTAT].n_value);
                else
                else
-                       routepr(nl[N_RTHOST].n_value, nl[N_RTNET].n_value);
+                       routepr((off_t)nl[N_RTHOST].n_value, 
+                               (off_t)nl[N_RTNET].n_value,
+                               (off_t)nl[N_RTHASHSIZE].n_value,
+                               (off_t)nl[N_RTREE].n_value);
                exit(0);
        }
                exit(0);
        }
+    if (af == AF_INET || af == AF_UNSPEC) {
        setprotoent(1);
        setservent(1);
        while (p = getprotoent()) {
        setprotoent(1);
        setservent(1);
        while (p = getprotoent()) {
-               register struct protox *tp;
 
                for (tp = protox; tp->pr_name; tp++)
                        if (strcmp(tp->pr_name, p->p_name) == 0)
                                break;
                if (tp->pr_name == 0 || tp->pr_wanted == 0)
                        continue;
 
                for (tp = protox; tp->pr_name; tp++)
                        if (strcmp(tp->pr_name, p->p_name) == 0)
                                break;
                if (tp->pr_name == 0 || tp->pr_wanted == 0)
                        continue;
-               if (sflag && tp->pr_stats) {
-                       (*tp->pr_stats)(nl[tp->pr_sindex].n_value, p->p_name);
-                       continue;
-               }
-               if (tp->pr_cblocks)
-                       (*tp->pr_cblocks)(nl[tp->pr_index].n_value, p->p_name);
+               if (sflag) {
+                       if (tp->pr_stats)
+                               (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
+                                       p->p_name);
+               } else
+                       if (tp->pr_cblocks)
+                               (*tp->pr_cblocks)(nl[tp->pr_index].n_value,
+                                       p->p_name);
        }
        endprotoent();
        }
        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 ((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);
+}
+
+
+char *
+plural(n)
+       int n;
+{
+
+       return (n != 1 ? "s" : "");
 }
 
 /*
 }
 
 /*
- * Seek into the kernel for a value.
+ * Find the protox for the given "well-known" name.
  */
  */
-klseek(fd, base, off)
-       int fd, base, off;
+struct protox *
+knownname(name)
+       char *name;
 {
 {
+       struct protox **tpp, *tp;
 
 
-       if (kflag) {
-               /* get kernel pte */
-#ifdef vax
-               base &= 0x7fffffff;
-#endif
-               base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
-       }
-       lseek(fd, base, off);
+       for (tpp = protoprotox; *tpp; tpp++)
+           for (tp = *tpp; tp->pr_name; tp++)
+               if (strcmp(tp->pr_name, name) == 0)
+                       return(tp);
+       return(NULLPROTOX);
 }
 
 }
 
-char *
-plural(n)
-       int n;
+/*
+ * Find the protox corresponding to name.
+ */
+struct protox *
+name2protox(name)
+       char *name;
 {
 {
+       struct protox *tp;
+       char **alias;                   /* alias from p->aliases */
+       struct protoent *p;
 
 
-       return (n != 1 ? "s" : "");
+       /*
+        * Try to find the name in the list of "well-known" names. If that
+        * fails, check if name is an alias for an Internet protocol.
+        */
+       if (tp = knownname(name))
+               return(tp);
+
+       setprotoent(1);                 /* make protocol lookup cheaper */
+       while (p = getprotoent()) {
+               /* assert: name not same as p->name */
+               for (alias = p->p_aliases; *alias; alias++)
+                       if (strcmp(name, *alias) == 0) {
+                               endprotoent();
+                               return(knownname(p->p_name));
+                       }
+       }
+       endprotoent();
+       return(NULLPROTOX);
+}
+
+usage()
+{
+       fputs("usage: netstat [-Aan] [-f address_family] [system] [core]\n               [-himnrs] [-f address_family] [system] [core]\n               [-n] [-I interface] interval [system] [core]\n", stderr);
+       exit(1);
 }
 }