not every value return in an nlist structure was being
[unix-history] / usr / src / usr.bin / netstat / main.c
index 765b9e2..5832f69 100644 (file)
@@ -1,14 +1,39 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)main.c     4.3 82/12/05";
-#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.30 (Berkeley) %G%";
+#endif /* not lint */
 
 #include <sys/param.h>
 
 #include <sys/param.h>
-#include <sys/pte.h>
+#include <sys/file.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
 #include <ctype.h>
 #include <errno.h>
 #include <ctype.h>
 #include <errno.h>
+#include <kvm.h>
+#include <limits.h>
 #include <netdb.h>
 #include <nlist.h>
 #include <netdb.h>
 #include <nlist.h>
+#include <paths.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
 
 struct nlist nl[] = {
 #define        N_MBSTAT        0
 
 struct nlist nl[] = {
 #define        N_MBSTAT        0
@@ -23,162 +48,303 @@ struct nlist nl[] = {
        { "_udb" },
 #define        N_UDPSTAT       5
        { "_udpstat" },
        { "_udb" },
 #define        N_UDPSTAT       5
        { "_udpstat" },
-#define        N_RAWCB         6
-       { "_rawcb" },
-#define        N_SYSMAP        7
-       { "_Sysmap" },
-#define        N_SYSSIZE       8
-       { "_Syssize" },
-#define        N_IFNET         9
+#define        N_IFNET         6
        { "_ifnet" },
        { "_ifnet" },
-#define        N_HOSTS         10
-       { "_hosts" },
-#define        N_RTHOST        11
-       { "_rthost" },
-#define        N_RTNET         12
-       { "_rtnet" },
-       0,
-};
+#define        N_IMP           7
+       { "_imp_softc" },
+#define        N_ICMPSTAT      8
+       { "_icmpstat" },
+#define        N_RTSTAT        9
+       { "_rtstat" },
+#define        N_UNIXSW        10
+       { "_unixsw" },
+#define N_IDP          11
+       { "_nspcb"},
+#define N_IDPSTAT      12
+       { "_idpstat"},
+#define N_SPPSTAT      13
+       { "_spp_istat"},
+#define N_NSERR                14
+       { "_ns_errstat"},
+#define        N_CLNPSTAT      15
+       { "_clnp_stat"},
+#define        IN_NOTUSED      16
+       { "_tp_inpcb" },
+#define        ISO_TP          17
+       { "_tp_refinfo" },
+#define        N_TPSTAT        18
+       { "_tp_stat" },
+#define        N_ESISSTAT      19
+       { "_esis_stat"},
+#define N_NIMP         20
+       { "_nimp"},
+#define N_RTREE                21
+       { "_rt_tables"},
+#define N_CLTP         22
+       { "_cltb"},
+#define N_CLTPSTAT     23
+       { "_cltpstat"},
+#define        N_NFILE         24
+       { "_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
+       { "_tcp" },
+#define        N_UDP           24
+       { "_udp" },
+#define N_RDP          25
+       { "_rdp" },
+#define        N_RDPSTAT       26
+       { "_rdpstat" },
 
 
-extern int protopr();
-extern int tcp_stats(), udp_stats(), ip_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 */
-} protox[] = {
+};
+
+struct  protox berkprotox[] = {
        { N_TCB,        N_TCPSTAT,      1,      protopr,
          tcp_stats,    "tcp" },
        { N_UDB,        N_UDPSTAT,      1,      protopr,
          udp_stats,    "udp" },
        { -1,           N_IPSTAT,       1,      0,
          ip_stats,     "ip" },
        { N_TCB,        N_TCPSTAT,      1,      protopr,
          tcp_stats,    "tcp" },
        { N_UDB,        N_UDPSTAT,      1,      protopr,
          udp_stats,    "udp" },
        { -1,           N_IPSTAT,       1,      0,
          ip_stats,     "ip" },
+       { -1,           N_ICMPSTAT,     1,      0,
+         icmp_stats,   "icmp" },
+       { -1,           -1,             0,      0,
+         0,            0 }
+};
+
+struct protox bbnprotox[] = {
+       { N_TCP,        N_TCPSTAT,      1,      bbnprotopr,
+         tcpstats,     "tcp" },
+       { N_UDP,        N_UDPSTAT,      1,      bbnprotopr,
+         udpstats,     "udp" },
+       { N_RDP,        N_RDPSTAT,      1,      bbnprotopr,
+         rdpstats,     "rdp" },
+       { N_RAWCB,      0,              1,      bbnprotopr,
+         0,            "raw" },
+       { -1,           N_IPSTAT,       1,      0,
+         ipstats,      "ip" },
+       { -1,           N_ICMPSTAT,     1,      0,
+         icmpstats,    "icmp" },
+       { -1,           -1,             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" },
+       { -1,           N_CLNPSTAT,     1,       0,
+         clnp_stats,   "clnp"},
+       { -1,           N_ESISSTAT,     1,       0,
+         esis_stats,   "esis"},
        { -1,           -1,             0,      0,
          0,            0 }
 };
 
        { -1,           -1,             0,      0,
          0,            0 }
 };
 
-struct pte *Sysmap;
-
-char   *system = "/vmunix";
-char   *kmemf = "/dev/kmem";
-int    kmem;
-int    kflag;
-int    Aflag;
-int    aflag;
-int    hflag;
-int    iflag;
-int    mflag;
-int    nflag;
-int    rflag;
-int    sflag;
-int    tflag;
-int    interval;
-char   usage[] = "[ -Aaihmnrst ] [ interval ] [ system ] [ core ]";
+struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
+
+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;
 main(argc, argv)
        int argc;
-       char *argv[];
+       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 */
+       register char *cp;
+       int ch;
+       char *nlistf = NULL, *memf = NULL;
+       char buf[_POSIX2_LINE_MAX];
 
 
-       name = argv[0];
-       argc--, argv++;
-       while (argc > 0 && **argv == '-') {
-               for (cp = &argv[0][1]; *cp; cp++)
-               switch(argv[0][1]) {
+       if (cp = rindex(argv[0], '/'))
+               prog = cp + 1;
+       else
+               prog = argv[0];
+       af = AF_UNSPEC;
 
 
+       while ((ch = getopt(argc, argv, "AaBdf:hI:iM:mN:np:rstuw")) != EOF)
+               switch((char)ch) {
                case 'A':
                case 'A':
-                       Aflag++;
+                       Aflag = 1;
                        break;
                        break;
-
                case 'a':
                case 'a':
-                       aflag++;
+                       aflag = 1;
+                       break;
+               case 'B':
+                       Bflag = 1;
+                       break;
+               case 'd':
+                       dflag = 1;
+                       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 {
+                               (void)fprintf(stderr,
+                                   "%s: %s: unknown address family\n",
+                                   prog, optarg);
+                               exit(1);
+                       }
                        break;
                        break;
-
                case 'h':
                case 'h':
-                       hflag++;
+                       hflag = 1;
                        break;
                        break;
+               case 'I': {
+                       char *cp;
 
 
+                       iflag = 1;
+                       for (cp = interface = optarg; isalpha(*cp); cp++)
+                               continue;
+                       unit = atoi(cp);
+                       *cp = '\0';
+                       break;
+               }
                case 'i':
                case 'i':
-                       iflag++;
+                       iflag = 1;
+                       break;
+               case 'M':
+                       memf = optarg;
                        break;
                        break;
-
                case 'm':
                case 'm':
-                       mflag++;
+                       mflag = 1;
+                       break;
+               case 'N':
+                       nlistf = optarg;
                        break;
                        break;
-
                case 'n':
                case 'n':
-                       nflag++;
+                       nflag = 1;
+                       break;
+               case 'p':
+                       if ((tp = name2protox(optarg)) == NULL) {
+                               (void)fprintf(stderr,
+                                   "%s: %s: unknown or uninstrumented protocol\n",
+                                   prog, optarg);
+                               exit(1);
+                       }
+                       pflag = 1;
                        break;
                        break;
-
                case 'r':
                case 'r':
-                       rflag++;
+                       rflag = 1;
                        break;
                        break;
-
                case 's':
                case 's':
-                       sflag++;
+                       ++sflag;
                        break;
                        break;
-
                case 't':
                case 't':
-                       tflag++;
+                       tflag = 1;
                        break;
                        break;
-
+               case 'u':
+                       af = AF_UNIX;
+                       break;
+               case 'w':
+                       interval = atoi(optarg);
+                       break;
+               case '?':
                default:
                default:
-use:
-                       printf("usage: %s %s\n", name, usage);
-                       exit(1);
+                       usage();
+               }
+       argv += optind;
+       argc -= optind;
+
+#define        BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+       if (*argv) {
+               if (isdigit(**argv)) {
+                       interval = atoi(*argv);
+                       if (interval <= 0)
+                               usage();
+                       ++argv;
+                       iflag = 1;
+               }
+               if (*argv) {
+                       nlistf = *argv;
+                       if (*++argv)
+                               memf = *argv;
                }
                }
-               argv++, argc--;
-       }
-       if (argc > 0 && isdigit(argv[0][0])) {
-               interval = atoi(argv[0]);
-               if (interval <= 0)
-                       goto use;
-               argv++, argc--;
-               iflag++;
-       }
-       if (argc > 0) {
-               system = *argv;
-               argv++, argc--;
        }
        }
-       nlist(system, nl);
-       if (nl[0].n_type == 0) {
-               fprintf(stderr, "%s: no namelist\n", system);
+#endif
+
+       /*
+        * Discard setgid privileges if not the running kernel so that bad
+        * guys can't print interesting stuff from kernel memory.
+        */
+       if (nlistf != NULL || memf != NULL)
+               setgid(getgid());
+
+       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 (argc > 0) {
-               kmemf = *argv;
-               kflag++;
-       }
-       kmem = open(kmemf, 0);
-       if (kmem < 0) {
-               fprintf(stderr, "cannot open ");
-               perror(kmemf);
+       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);
        }
                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) {
                mbpr(nl[N_MBSTAT].n_value);
                exit(0);
        }
        if (mflag) {
                mbpr(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);
+       }
        /*
         * Keep file descriptors open to avoid overhead
         * of open/close on each call to get* routines.
        /*
         * Keep file descriptors open to avoid overhead
         * of open/close on each call to get* routines.
@@ -189,45 +355,125 @@ 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);
+       if (rflag) {
+               if (sflag)
+                       rt_stats(nl[N_RTSTAT].n_value);
+               else
+                       routepr(nl[N_RTREE].n_value);
                exit(0);
        }
                exit(0);
        }
-       if (rflag) {
-               routepr(nl[N_RTHOST].n_value, nl[N_RTNET].n_value);
+       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);
        }
-       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;
-               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, tp->pr_name);
+               } else if (tp->pr_cblocks)
+                       (*tp->pr_cblocks)(nl[tp->pr_index].n_value, tp->pr_name);
        }
        }
-       endprotoent();
+       if (pr != NULL && (off || af != AF_UNSPEC))
+               (*pr)(off, name);
 }
 
 /*
 }
 
 /*
- * Seek into the kernel for a value.
+ * Read kernel memory, return 0 on success.
  */
  */
-klseek(fd, base, off)
-       int fd, base, off;
+int
+kread(addr, buf, size)
+       u_long addr;
+       char *buf;
+       int size;
 {
 
 {
 
-       if (kflag) {
-               /* get kernel pte */
-               base &= 0x7fffffff;
-               base = Sysmap[base >> 9].pg_pfnum * 512 + (base & 0x1ff);
+       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);
        }
        }
-       lseek(fd, base, off);
+       return (0);
+}
+
+char *
+plural(n)
+       int n;
+{
+       return (n != 1 ? "s" : "");
+}
+
+char *
+plurales(n)
+       int n;
+{
+       return (n != 1 ? "es" : "");
+}
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+static struct protox *
+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);
+}
+
+/*
+ * Find the protox corresponding to name.
+ */
+static struct protox *
+name2protox(name)
+       char *name;
+{
+       struct protox *tp;
+       char **alias;                   /* alias from p->aliases */
+       struct protoent *p;
+
+       /*
+        * 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 (NULL);
+}
+
+static void
+usage()
+{
+       (void)fprintf(stderr,
+"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,
+"               [-n] [-I interface] [-M core] [-N system] [-w wait]\n");
+       (void)fprintf(stderr,
+"               [-M core] [-N system] [-p protocol]\n");
+       exit(1);
 }
 }