not every value return in an nlist structure was being
[unix-history] / usr / src / usr.bin / netstat / main.c
index 29ae13f..5832f69 100644 (file)
@@ -1,35 +1,39 @@
 /*
 /*
- * Copyright (c) 1983,1988 Regents of the University of California.
+ * Copyright (c) 1983, 1988 Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is given
- * to the University of California at Berkeley. The name of the University
- * may not be used to endorse or promote products derived from this
- * software without specific prior written permission. This software
- * is provided ``as is'' without express or implied warranty.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.12 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     5.30 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
-#include <sys/vmmac.h>
-#include <sys/socket.h>
 #include <sys/file.h>
 #include <sys/file.h>
-#include <machine/pte.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
@@ -44,42 +48,56 @@ 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_IMP           10
+#define        N_IMP           7
        { "_imp_softc" },
        { "_imp_softc" },
-#define        N_RTHOST        11
-       { "_rthost" },
-#define        N_RTNET         12
-       { "_rtnet" },
-#define        N_ICMPSTAT      13
+#define        N_ICMPSTAT      8
        { "_icmpstat" },
        { "_icmpstat" },
-#define        N_RTSTAT        14
+#define        N_RTSTAT        9
        { "_rtstat" },
        { "_rtstat" },
-#define        N_NFILE         15
-       { "_nfile" },
-#define        N_FILE          16
-       { "_file" },
-#define        N_UNIXSW        17
+#define        N_UNIXSW        10
        { "_unixsw" },
        { "_unixsw" },
-#define N_RTHASHSIZE   18
-       { "_rthashsize" },
-#define N_IDP          19
+#define N_IDP          11
        { "_nspcb"},
        { "_nspcb"},
-#define N_IDPSTAT      20
+#define N_IDPSTAT      12
        { "_idpstat"},
        { "_idpstat"},
-#define N_SPPSTAT      21
+#define N_SPPSTAT      13
        { "_spp_istat"},
        { "_spp_istat"},
-#define N_NSERR                22
+#define N_NSERR                14
        { "_ns_errstat"},
        { "_ns_errstat"},
-#define N_NIMP         23
+#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"},
        { "_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
 
     /* BBN Internet protocol implementation */
 #define        N_TCP           23
@@ -94,21 +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();
-
-#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 */
        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 */
 };
 
@@ -153,58 +162,61 @@ struct protox nsprotox[] = {
          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    pflag;
-int    rflag;
-int    sflag;
-int    tflag;
-int    interval;
-char   *interface;
-int    unit;
-
-int    af = AF_UNSPEC;
-
-extern char *malloc();
-extern off_t lseek();
+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 }
+};
+
+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;
 {
        extern char *optarg;
        extern int optind;
        register struct protoent *p;
        register struct protox *tp;     /* for printing cblocks & stats */
 {
        extern char *optarg;
        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;
+       char *nlistf = NULL, *memf = NULL;
+       char buf[_POSIX2_LINE_MAX];
 
 
-       while ((ch = getopt(argc, argv, "AI:af:himnp:rstu")) != EOF)
+       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':
                switch((char)ch) {
                case 'A':
-                       Aflag++;
-                       break;
-               case 'I': {
-                       char *cp;
-
-                       iflag++;
-                       for (cp = interface = optarg; isalpha(*cp); cp++);
-                       unit = atoi(cp);
-                       *cp = '\0';
+                       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)
                        break;
                case 'f':
                        if (strcmp(optarg, "ns") == 0)
@@ -213,42 +225,67 @@ main(argc, argv)
                                af = AF_INET;
                        else if (strcmp(optarg, "unix") == 0)
                                af = AF_UNIX;
                                af = AF_INET;
                        else if (strcmp(optarg, "unix") == 0)
                                af = AF_UNIX;
+                       else if (strcmp(optarg, "iso") == 0)
+                               af = AF_ISO;
                        else {
                        else {
-                               fprintf(stderr, "%s: unknown address family\n", optarg);
-                               exit(10);
+                               (void)fprintf(stderr,
+                                   "%s: %s: unknown address family\n",
+                                   prog, optarg);
+                               exit(1);
                        }
                        break;
                case 'h':
                        }
                        break;
                case 'h':
-                       hflag++;
+                       hflag = 1;
+                       break;
+               case 'I': {
+                       char *cp;
+
+                       iflag = 1;
+                       for (cp = interface = optarg; isalpha(*cp); cp++)
+                               continue;
+                       unit = atoi(cp);
+                       *cp = '\0';
                        break;
                        break;
+               }
                case 'i':
                case 'i':
-                       iflag++;
+                       iflag = 1;
+                       break;
+               case 'M':
+                       memf = optarg;
                        break;
                case 'm':
                        break;
                case 'm':
-                       mflag++;
+                       mflag = 1;
+                       break;
+               case 'N':
+                       nlistf = optarg;
                        break;
                case 'n':
                        break;
                case 'n':
-                       nflag++;
+                       nflag = 1;
                        break;
                case 'p':
                        break;
                case 'p':
-                       if ((tp = name2protox(optarg)) == NULLPROTOX) {
-                               fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg);
-                               exit(10);
+                       if ((tp = name2protox(optarg)) == NULL) {
+                               (void)fprintf(stderr,
+                                   "%s: %s: unknown or uninstrumented protocol\n",
+                                   prog, optarg);
+                               exit(1);
                        }
                        }
-                       pflag++;
+                       pflag = 1;
                        break;
                case 'r':
                        break;
                case 'r':
-                       rflag++;
+                       rflag = 1;
                        break;
                case 's':
                        break;
                case 's':
-                       sflag++;
+                       ++sflag;
                        break;
                case 't':
                        break;
                case 't':
-                       tflag++;
+                       tflag = 1;
                        break;
                case 'u':
                        af = AF_UNIX;
                        break;
                        break;
                case 'u':
                        af = AF_UNIX;
                        break;
+               case 'w':
+                       interval = atoi(optarg);
+                       break;
                case '?':
                default:
                        usage();
                case '?':
                default:
                        usage();
@@ -256,48 +293,44 @@ main(argc, argv)
        argv += optind;
        argc -= optind;
 
        argv += optind;
        argc -= optind;
 
-       if (argc > 0) {
-               if (isdigit(argv[0][0])) {
-                       interval = atoi(argv[0]);
+#define        BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+       if (*argv) {
+               if (isdigit(**argv)) {
+                       interval = atoi(*argv);
                        if (interval <= 0)
                                usage();
                        if (interval <= 0)
                                usage();
-                       argv++, argc--;
-                       iflag++;
+                       ++argv;
+                       iflag = 1;
                }
                }
-               if (argc > 0) {
-                       system = *argv;
-                       argv++, argc--;
-                       if (argc > 0) {
-                               kmemf = *argv;
-                               kflag++;
-                       }
+               if (*argv) {
+                       nlistf = *argv;
+                       if (*++argv)
+                               memf = *argv;
                }
        }
                }
        }
-       if (nlist(system, nl) < 0 || 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);
        }
-       kmem = open(kmemf, O_RDONLY);
-       if (kmem < 0) {
-               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;
-
-               Sysmap = (struct pte *)
-                  malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
-               if (!Sysmap) {
-                       fputs("netstat: can't get memory for Sysmap.\n", stderr);
-                       exit(1);
-               }
-               off = nl[N_SYSMAP].n_value & ~KERNBASE;
-               (void)lseek(kmem, off, L_SET);
-               (void)read(kmem, (char *)Sysmap,
-                   (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
-       }
        if (mflag) {
        if (mflag) {
-               mbpr((off_t)nl[N_MBSTAT].n_value);
+               mbpr(nl[N_MBSTAT].n_value);
                exit(0);
        }
        if (pflag) {
                exit(0);
        }
        if (pflag) {
@@ -324,23 +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_RTHOST].n_value, 
-                               (off_t)nl[N_RTNET].n_value,
-                               (off_t)nl[N_RTHASHSIZE].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)
@@ -348,74 +380,63 @@ 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_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);
+       if (pr != NULL && (off || af != AF_UNSPEC))
+               (*pr)(off, name);
 }
 
 /*
 }
 
 /*
- * Seek into the kernel for a value.
+ * Read kernel memory, return 0 on success.
  */
  */
-off_t
-klseek(fd, base, off)
-       int fd, off;
-       off_t base;
+int
+kread(addr, buf, size)
+       u_long addr;
+       char *buf;
+       int size;
 {
 {
-       if (kflag) {
-               /* get kernel pte */
-               base &= ~KERNBASE;
-               base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
+
+       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);
        }
        }
-       return (lseek(fd, base, off));
+       return (0);
 }
 
 char *
 plural(n)
        int n;
 {
 }
 
 char *
 plural(n)
        int 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;
 {
 knownname(name)
        char *name;
 {
-       struct protox *tp;
+       struct protox **tpp, *tp;
 
 
-       for (tp = protox; tp->pr_name; tp++)
-               if (strcmp(tp->pr_name, name) == 0)
-                       return(tp);
-       for (tp = nsprotox; tp->pr_name; tp++)
-               if (strcmp(tp->pr_name, name) == 0)
-                       return(tp);
-       return(NULLPROTOX);
+       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.
  */
 }
 
 /*
  * Find the protox corresponding to name.
  */
-struct protox *
+static struct protox *
 name2protox(name)
        char *name;
 {
 name2protox(name)
        char *name;
 {
@@ -428,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()) {
@@ -436,15 +457,23 @@ 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(NULLPROTOX);
+       return (NULL);
 }
 
 }
 
+static void
 usage()
 {
 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);
+       (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);
 }
        exit(1);
 }