BSD 4_3_Tahoe release
[unix-history] / usr / src / ucb / netstat / main.c
index b421cf4..be3b13b 100644 (file)
@@ -1,22 +1,34 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * 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 the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, 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'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #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";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.7 (Berkeley) 5/22/86";
-#endif not lint
+static char sccsid[] = "@(#)main.c     5.14 (Berkeley) 6/29/88";
+#endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/vmmac.h>
 #include <sys/socket.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 <machine/pte.h>
 #include <ctype.h>
 #include <errno.h>
@@ -45,8 +57,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
@@ -71,15 +83,19 @@ struct nlist nl[] = {
        { "_spp_istat"},
 #define N_NSERR                22
        { "_ns_errstat"},
        { "_spp_istat"},
 #define N_NSERR                22
        { "_ns_errstat"},
+#define N_NIMP         23
+       { "_nimp"},
        "",
 };
 
 /* internet protocols */
 extern int protopr();
 extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
        "",
 };
 
 /* internet protocols */
 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();
 
 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 */
 struct protox {
        u_char  pr_index;               /* index into nlist of cb head */
        u_char  pr_sindex;              /* index into nlist of stat block */
@@ -123,150 +139,155 @@ 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    fflag;
+int    dflag;
 int    interval;
 char   *interface;
 int    unit;
 int    interval;
 char   *interface;
 int    unit;
-char   usage[] = "[ -Aaihmnrst ] [-f address_family] [-I interface] [ interval ] [ system ] [ core ]";
 
 int    af = AF_UNSPEC;
 
 
 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;
-
-       name = argv[0];
-       argc--, argv++;
-       while (argc > 0 && **argv == '-') {
-               for (cp = &argv[0][1]; *cp; cp++)
-               switch(*cp) {
+       register struct protox *tp;     /* for printing cblocks & stats */
+       struct protox *name2protox();   /* for -p */
+       int ch;
 
 
+       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 {
+                               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 'u':
                        af = AF_UNIX;
                        break;
+               case '?':
+               default:
+                       usage();
+               }
+       argv += optind;
+       argc -= optind;
 
 
-               case 'f':
-                       argv++;
-                       argc--;
-                       if (strcmp(*argv, "ns") == 0)
-                               af = AF_NS;
-                       else if (strcmp(*argv, "inet") == 0)
-                               af = AF_INET;
-                       else if (strcmp(*argv, "unix") == 0)
-                               af = AF_UNIX;
-                       else {
-                               fprintf(stderr, "%s: unknown address family\n",
-                                       *argv);
-                               exit(10);
-                       }
-                       break;
-                       
-               case 'I':
+       if (argc > 0) {
+               if (isdigit(argv[0][0])) {
+                       interval = atoi(argv[0]);
+                       if (interval <= 0)
+                               usage();
+                       argv++, argc--;
                        iflag++;
                        iflag++;
-                       if (*(interface = cp + 1) == 0) {
-                               if ((interface = argv[1]) == 0)
-                                       break;
-                               argv++;
-                               argc--;
+               }
+               if (argc > 0) {
+                       system = *argv;
+                       argv++, argc--;
+                       if (argc > 0) {
+                               kmemf = *argv;
+                               kflag++;
                        }
                        }
-                       for (cp = interface; isalpha(*cp); cp++)
-                               ;
-                       unit = atoi(cp);
-                       *cp-- = 0;
-                       break;
-
-               default:
-use:
-                       printf("usage: %s %s\n", name, usage);
-                       exit(1);
                }
                }
-               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) {
+       if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
                fprintf(stderr, "%s: no namelist\n", system);
                exit(1);
        }
                fprintf(stderr, "%s: no namelist\n", system);
                exit(1);
        }
-       if (argc > 0) {
-               kmemf = *argv;
-               kflag++;
-       }
-       kmem = open(kmemf, 0);
+       kmem = open(kmemf, O_RDONLY);
        if (kmem < 0) {
        if (kmem < 0) {
-               fprintf(stderr, "cannot open ");
                perror(kmemf);
                exit(1);
        }
        if (kflag) {
                off_t off;
 
                perror(kmemf);
                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");
+               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);
                }
                        exit(1);
                }
-               read(kmem, Sysmap, nl[N_SYSSIZE].n_value);
+               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(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);
        }
        /*
@@ -279,16 +300,13 @@ 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,
-                               nl[N_RTHASHSIZE].n_value);
+                       routepr((off_t)nl[N_RTHOST].n_value, 
+                               (off_t)nl[N_RTNET].n_value,
+                               (off_t)nl[N_RTHASHSIZE].n_value);
                exit(0);
        }
     if (af == AF_INET || af == AF_UNSPEC) {
                exit(0);
        }
     if (af == AF_INET || af == AF_UNSPEC) {
@@ -325,26 +343,27 @@ use:
        }
     }
     if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
        }
     }
     if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
-           unixpr(nl[N_NFILE].n_value, nl[N_FILE].n_value,
-               nl[N_UNIXSW].n_value);
+           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);
 }
 
 /*
  * Seek into the kernel for a value.
  */
     exit(0);
 }
 
 /*
  * Seek into the kernel for a value.
  */
+off_t
 klseek(fd, base, off)
 klseek(fd, base, off)
-       int fd, base, off;
+       int fd, off;
+       off_t base;
 {
 {
-
        if (kflag) {
                /* get kernel pte */
        if (kflag) {
                /* get kernel pte */
-#ifdef vax
-               base &= 0x7fffffff;
-#endif
+               base &= ~KERNBASE;
                base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
        }
                base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
        }
-       lseek(fd, base, off);
+       return (lseek(fd, base, off));
 }
 
 char *
 }
 
 char *
@@ -354,3 +373,58 @@ plural(n)
 
        return (n != 1 ? "s" : "");
 }
 
        return (n != 1 ? "s" : "");
 }
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+struct protox *
+knownname(name)
+       char *name;
+{
+       struct protox *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);
+}
+
+/*
+ * Find the protox corresponding to name.
+ */
+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(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);
+}