4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / usr.sbin / pstat / pstat.c
index f477fa0..4b1d78f 100644 (file)
-static char *sccsid = "@(#)pstat.c     4.6 (Berkeley) %G%";
-/*
- * Print system stuff
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * %sccs.include.redist.c%
  */
 
  */
 
-#define mask(x) (x&0377)
-#define        clear(x) ((int)x&0x7fffffff)
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pstat.c    8.1 (Berkeley) %G%";
+#endif /* not lint */
 
 #include <sys/param.h>
 
 #include <sys/param.h>
-#include <sys/dir.h>
-#include <sys/file.h>
-#include <sys/user.h>
-#include <sys/proc.h>
-#include <sys/text.h>
-#include <sys/inode.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
 #include <sys/map.h>
 #include <sys/map.h>
+#define KERNEL
+#include <sys/file.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#undef KERNEL
+#define NFS
+#include <sys/mount.h>
+#undef NFS
+#include <sys/stat.h>
+#include <nfs/nfsnode.h>
+#include <sys/ioctl.h>
 #include <sys/tty.h>
 #include <sys/conf.h>
 #include <sys/tty.h>
 #include <sys/conf.h>
-#include <sys/vm.h>
+
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <kvm.h>
+#include <limits.h>
 #include <nlist.h>
 #include <nlist.h>
-#include <sys/pte.h>
-#define        KERNEL
-#include <sys/mx.h>
-#undef KERNEL
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 
-char   *fcore  = "/dev/kmem";
-char   *fnlist = "/vmunix";
-int    fc;
+#include "pathnames.h"
 
 struct nlist nl[] = {
 
 struct nlist nl[] = {
-#define        SINODE  0
-       { "_inode" },
-#define        STEXT   1
-       { "_text" },
-#define        SPROC   2
-       { "_proc" },
-#define        SDZ     3
-       { "_dz_tty" },
-#define        SNDZ    4
-       { "_dz_cnt" },
-#define        SKL     5
+#define VM_SWAPMAP     0
+       { "_swapmap" }, /* list of free swap areas */
+#define VM_NSWAPMAP    1
+       { "_nswapmap" },/* size of the swap map */
+#define VM_SWDEVT      2
+       { "_swdevt" },  /* list of swap devices and sizes */
+#define VM_NSWAP       3
+       { "_nswap" },   /* size of largest swap device */
+#define VM_NSWDEV      4
+       { "_nswdev" },  /* number of swap devices */
+#define VM_DMMAX       5
+       { "_dmmax" },   /* maximum size of a swap block */
+#define V_NUMV         6
+       { "_numvnodes" },
+#define V_ROOTFS       7
+       { "_rootfs" },
+#define        FNL_NFILE       8
+       {"_nfiles"},
+#define FNL_MAXFILE    9
+       {"_maxfiles"},
+#define NLMANDATORY FNL_MAXFILE        /* names up to here are mandatory */
+#define        SCONS   NLMANDATORY + 1
        { "_cons" },
        { "_cons" },
-#define        SFIL    6
-       { "_file" },
-#define        USRPTMA 7
-       { "_Usrptmap" },
-#define        USRPT   8
-       { "_usrpt" },
-#define        SNSWAP  9
-       { "_nswap" },
-#define        SWAPMAP 10
-       { "_swapmap" },
-#define        SDH     11
-       { "_dh11" },
-#define        SNDH    12
-       { "_ndh11" },
-#define        SGROUP  13
-       { "_groups" },
-#define        SCHANS  14
-       { "_chans" },
-#define        SSCHANS 15
-       { "_schans" },
-#define        SNPROC  16
-       { "_nproc" },
-#define        SNTEXT  17
-       { "_ntext" },
-#define        SNFILE  18
-       { "_nfile" },
-#define        SNINODE 19
-       { "_ninode" },
-#define        SNSWAPMAP 20
-       { "_nswapmap" },
-       0,
-};
+#define        SPTY    NLMANDATORY + 2
+       { "_pt_tty" },
+#define        SNPTY   NLMANDATORY + 3
+       { "_npty" },
 
 
-int    inof;
-int    txtf;
-int    prcf;
-int    ttyf;
-int    usrf;
-int    mpxf;
-int    groupf;
-long   ubase;
-int    filf;
-int    swpf;
-int    totflg;
-char   partab[1];
-struct cdevsw  cdevsw[1];
-struct bdevsw  bdevsw[1];
-int    allflg;
-int    kflg;
-struct pte *Usrptma;
-struct pte *usrpt;
+#ifdef hp300
+#define        SDCA    (SNPTY+1)
+       { "_dca_tty" },
+#define        SNDCA   (SNPTY+2)
+       { "_ndca" },
+#define        SDCM    (SNPTY+3)
+       { "_dcm_tty" },
+#define        SNDCM   (SNPTY+4)
+       { "_ndcm" },
+#define        SDCL    (SNPTY+5)
+       { "_dcl_tty" },
+#define        SNDCL   (SNPTY+6)
+       { "_ndcl" },
+#define        SITE    (SNPTY+7)
+       { "_ite_tty" },
+#define        SNITE   (SNPTY+8)
+       { "_nite" },
+#endif
 
 
-main(argc, argv)
-char **argv;
-{
-       register char *argp;
+#ifdef mips
+#define SDC    (SNPTY+1)
+       { "_dc_tty" },
+#define SNDC   (SNPTY+2)
+       { "_dc_cnt" },
+#endif
 
 
-       argc--, argv++;
-       while (argc > 0 && **argv == '-') {
-               argp = *argv++;
-               argp++;
-               argc--;
-               while (*argp++)
-               switch (argp[-1]) {
-
-               case 'T':
-                       totflg++;
-                       break;
+       { "" }
+};
 
 
-               case 'a':
-                       allflg++;
-                       break;
+int    usenumflag;
+int    totalflag;
+char   *nlistf = NULL;
+char   *memf   = NULL;
+kvm_t  *kd;
 
 
-               case 'i':
-                       inof++;
-                       break;
+#define        SVAR(var) __STRING(var) /* to force expansion */
+#define        KGET(idx, var)                                                  \
+       KGET1(idx, &var, sizeof(var), SVAR(var))
+#define        KGET1(idx, p, s, msg)                                           \
+       KGET2(nl[idx].n_value, p, s, msg)
+#define        KGET2(addr, p, s, msg)                                          \
+       if (kvm_read(kd, (u_long)(addr), p, s) != s)                    \
+               warnx("cannot read %s: %s", msg, kvm_geterr(kd))
+#define        KGETRET(addr, p, s, msg)                                        \
+       if (kvm_read(kd, (u_long)(addr), p, s) != s) {                  \
+               warnx("cannot read %s: %s", msg, kvm_geterr(kd));       \
+               return (0);                                             \
+       }
 
 
-               case 'k':
-                       kflg++;
-                       fcore = "/vmcore";
-                       break;
+void   filemode __P((void));
+int    getfiles __P((char **, int *));
+struct mount *
+       getmnt __P((struct mount *));
+struct e_vnode *
+       kinfo_vnodes __P((int *));
+struct e_vnode *
+       loadvnodes __P((int *));
+void   mount_print __P((struct mount *));
+void   nfs_header __P((void));
+int    nfs_print __P((struct vnode *));
+void   swapmode __P((void));
+void   ttymode __P((void));
+void   ttyprt __P((struct tty *, int));
+void   ttytype __P((struct tty *, char *, int, int));
+void   ufs_header __P((void));
+int    ufs_print __P((struct vnode *));
+void   usage __P((void));
+void   vnode_header __P((void));
+void   vnode_print __P((struct vnode *, struct vnode *));
+void   vnodemode __P((void));
 
 
-               case 'x':
-                       txtf++;
-                       break;
+int
+main(argc, argv)
+       int argc;
+       char *argv[];
+{
+       extern char *optarg;
+       extern int optind;
+       int ch, i, quit, ret;
+       int fileflag, swapflag, ttyflag, vnodeflag;
+       char buf[_POSIX2_LINE_MAX];
 
 
-               case 'p':
-                       prcf++;
+       fileflag = swapflag = ttyflag = vnodeflag = 0;
+       while ((ch = getopt(argc, argv, "TM:N:finstv")) != EOF)
+               switch (ch) {
+               case 'f':
+                       fileflag = 1;
                        break;
                        break;
-
-               case 't':
-                       ttyf++;
+               case 'M':
+                       memf = optarg;
                        break;
                        break;
-
-               case 'u':
-                       if (argc == 0)
-                               break;
-                       argc--;
-                       usrf++;
-                       sscanf( *argv++, "%x", &ubase);
+               case 'N':
+                       nlistf = optarg;
                        break;
                        break;
-
-               case 'f':
-                       filf++;
+               case 'n':
+                       usenumflag = 1;
                        break;
                case 's':
                        break;
                case 's':
-                       swpf++;
+                       swapflag = 1;
                        break;
                        break;
-               case 'm':
-                       mpxf++;
+               case 'T':
+                       totalflag = 1;
+                       break;
+               case 't':
+                       ttyflag = 1;
                        break;
                        break;
-               case 'g':
-                       groupf++;
+               case 'v':
+               case 'i':               /* Backward compatibility. */
+                       vnodeflag = 1;
                        break;
                        break;
+               default:
+                       usage();
                }
                }
+       argc -= optind;
+       argv += optind;
+
+       /*
+        * 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)
+               (void)setgid(getgid());
+
+       if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
+               errx(1, "kvm_openfiles: %s", buf);
+       if ((ret = kvm_nlist(kd, nl)) != 0) {
+               if (ret == -1)
+                       errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+               for (i = quit = 0; i <= NLMANDATORY; i++)
+                       if (!nl[i].n_value) {
+                               quit = 1;
+                               warnx("undefined symbol: %s\n", nl[i].n_name);
+                       }
+               if (quit)
+                       exit(1);
        }
        }
-       if (argc>0)
-               fcore = argv[0];
-       if ((fc = open(fcore, 0)) < 0) {
-               printf("Can't find %s\n", fcore);
-               exit(1);
-       }
-       if (argc>1)
-               fnlist = argv[1];
-       nlist(fnlist, nl);
-       if (kflg) {
-               register struct nlist *nlp;
-               for (nlp=nl; nlp < &nl[sizeof (nl)/sizeof(nl[0])]; nlp++)
-                       nlp->n_value = clear(nlp->n_value);
-       }
-       usrpt = (struct pte *)nl[USRPT].n_value;
-       Usrptma = (struct pte *)nl[USRPTMA].n_value;
-       if (nl[0].n_type == 0) {
-               printf("no namelist\n");
-               exit(1);
-       }
-       if (filf||totflg)
-               dofile();
-       if (inof||totflg)
-               doinode();
-       if (prcf||totflg)
-               doproc();
-       if (txtf||totflg)
-               dotext();
-       if (ttyf)
-               dotty();
-       if (usrf)
-               dousr();
-       if (swpf||totflg)
-               doswap();
-       if (mpxf)
-               dompx();
-       if (groupf)
-               dogroup();
+       if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
+               usage();
+       if (fileflag || totalflag)
+               filemode();
+       if (vnodeflag || totalflag)
+               vnodemode();
+       if (ttyflag)
+               ttymode();
+       if (swapflag || totalflag)
+               swapmode();
+       exit (0);
 }
 
 }
 
-doinode()
+struct e_vnode {
+       struct vnode *avnode;
+       struct vnode vnode;
+};
+
+void
+vnodemode()
 {
 {
-       register struct inode *ip;
-       struct inode *xinode, *ainode;
-       register int nin;
-       int ninode;
-
-       nin = 0;
-       ninode = getw(nl[SNINODE].n_value);
-       xinode = (struct inode *)calloc(ninode, sizeof (struct inode));
-       lseek(fc, (int)(ainode = (struct inode *)getw(nl[SINODE].n_value)), 0);
-       read(fc, xinode, ninode * sizeof(struct inode));
-       for (ip = xinode; ip < &xinode[ninode]; ip++)
-               if (ip->i_count)
-                       nin++;
-       if (totflg) {
-               printf("%3d/%3d inodes\n", nin, ninode);
+       register struct e_vnode *e_vnodebase, *endvnode, *evp;
+       register struct vnode *vp;
+       register struct mount *maddr, *mp;
+       int numvnodes;
+
+       e_vnodebase = loadvnodes(&numvnodes);
+       if (totalflag) {
+               (void)printf("%7d vnodes\n", numvnodes);
                return;
        }
                return;
        }
-       printf("%d/%d active inodes\n", nin, ninode);
-       printf("   LOC    FLAGS  CNT DEVICE   INO  MODE  NLK UID   SIZE/DEV\n");
-       for (ip = xinode; ip < &xinode[ninode]; ip++) {
-               if (ip->i_count == 0)
-                       continue;
-               printf("%8.1x ", ainode + (ip - xinode));
-               putf(ip->i_flag&ILOCK, 'L');
-               putf(ip->i_flag&IUPD, 'U');
-               putf(ip->i_flag&IACC, 'A');
-               putf(ip->i_flag&IMOUNT, 'M');
-               putf(ip->i_flag&IWANT, 'W');
-               putf(ip->i_flag&ITEXT, 'T');
-               printf("%4d", ip->i_count&0377);
-               printf("%4d,%3d", major(ip->i_dev), minor(ip->i_dev));
-               printf("%6d", ip->i_number);
-               printf("%6x", ip->i_mode & 0xffff);
-               printf("%4d", ip->i_nlink);
-               printf("%4d", ip->i_uid);
-               if ((ip->i_mode&IFMT)==IFBLK || (ip->i_mode&IFMT)==IFCHR)
-                       printf("%6d,%3d", major(ip->i_un.i_rdev), minor(ip->i_un.i_rdev));
-               else
-                       printf("%10ld", ip->i_size);
-               printf("\n");
+       endvnode = e_vnodebase + numvnodes;
+       (void)printf("%d active vnodes\n", numvnodes);
+
+
+#define ST     mp->mnt_stat
+       maddr = NULL;
+       for (evp = e_vnodebase; evp < endvnode; evp++) {
+               vp = &evp->vnode;
+               if (vp->v_mount != maddr) {
+                       /*
+                        * New filesystem
+                        */
+                       if ((mp = getmnt(vp->v_mount)) == NULL)
+                               continue;
+                       maddr = vp->v_mount;
+                       mount_print(mp);
+                       vnode_header();
+                       switch(ST.f_type) {
+                       case MOUNT_UFS:
+                       case MOUNT_MFS:
+                               ufs_header();
+                               break;
+                       case MOUNT_NFS:
+                               nfs_header();
+                               break;
+                       case MOUNT_NONE:
+                       case MOUNT_PC:
+                       default:
+                               break;
+                       }
+                       (void)printf("\n");
+               }
+               vnode_print(evp->avnode, vp);
+               switch(ST.f_type) {
+               case MOUNT_UFS:
+               case MOUNT_MFS:
+                       ufs_print(vp);
+                       break;
+               case MOUNT_NFS:
+                       nfs_print(vp);
+                       break;
+               case MOUNT_NONE:
+               case MOUNT_PC:
+               default:
+                       break;
+               }
+               (void)printf("\n");
        }
        }
-       free(xinode);
+       free(e_vnodebase);
 }
 
 }
 
-getw(loc)
-       off_t loc;
+void
+vnode_header()
 {
 {
-       int word;
-
-       lseek(fc, loc, 0);
-       read(fc, &word, sizeof (word));
-       return (word);
+       (void)printf("ADDR     TYP VFLAG  USE HOLD");
 }
 
 }
 
-putf(v, n)
+void
+vnode_print(avnode, vp)
+       struct vnode *avnode;
+       struct vnode *vp;
 {
 {
-       if (v)
-               printf("%c", n);
-       else
-               printf(" ");
+       char *type, flags[16]; 
+       char *fp = flags;
+       register int flag;
+
+       /*
+        * set type
+        */
+       switch(vp->v_type) {
+       case VNON:
+               type = "non"; break;
+       case VREG:
+               type = "reg"; break;
+       case VDIR:
+               type = "dir"; break;
+       case VBLK:
+               type = "blk"; break;
+       case VCHR:
+               type = "chr"; break;
+       case VLNK:
+               type = "lnk"; break;
+       case VSOCK:
+               type = "soc"; break;
+       case VFIFO:
+               type = "fif"; break;
+       case VBAD:
+               type = "bad"; break;
+       default: 
+               type = "unk"; break;
+       }
+       /*
+        * gather flags
+        */
+       flag = vp->v_flag;
+       if (flag & VROOT)
+               *fp++ = 'R';
+       if (flag & VTEXT)
+               *fp++ = 'T';
+       if (flag & VSYSTEM)
+               *fp++ = 'S';
+       if (flag & VXLOCK)
+               *fp++ = 'L';
+       if (flag & VXWANT)
+               *fp++ = 'W';
+       if (flag & VBWAIT)
+               *fp++ = 'B';
+       if (flag & VALIASED)
+               *fp++ = 'A';
+       if (flag == 0)
+               *fp++ = '-';
+       *fp = '\0';
+       (void)printf("%8x %s %5s %4d %4d",
+           avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
 }
 
 }
 
-dotext()
+void
+ufs_header() 
 {
 {
-       register struct text *xp;
-       int ntext;
-       struct text *xtext, *atext;
-       int ntx;
-
-       ntx = 0;
-       ntext = getw(nl[SNTEXT].n_value);
-       xtext = (struct text *)calloc(ntext, sizeof (struct text));
-       lseek(fc, (int)(atext = (struct text *)getw(nl[STEXT].n_value)), 0);
-       read(fc, xtext, ntext * sizeof (struct text));
-       for (xp = xtext; xp < &xtext[ntext]; xp++)
-               if (xp->x_iptr!=NULL)
-                       ntx++;
-       if (totflg) {
-               printf("%3d/%3d texts\n", ntx, ntext);
-               return;
-       }
-       printf("%d/%d active texts\n", ntx, ntext);
-       printf("   LOC   FLAGS DADDR      CADDR  RSS SIZE      IPTR  CNT CCNT\n");
-       for (xp = xtext; xp < &xtext[ntext]; xp++) {
-               if (xp->x_iptr == NULL)
-                       continue;
-               printf("%8.1x", atext + (xp - xtext));
-               printf(" ");
-               putf(xp->x_flag&XPAGI, 'P');
-               putf(xp->x_flag&XTRC, 'T');
-               putf(xp->x_flag&XWRIT, 'W');
-               putf(xp->x_flag&XLOAD, 'L');
-               putf(xp->x_flag&XLOCK, 'K');
-               putf(xp->x_flag&XWANT, 'w');
-               printf("%5x", xp->x_daddr[0]);
-               printf("%11x", xp->x_caddr);
-               printf("%5d", xp->x_rssize);
-               printf("%5d", xp->x_size);
-               printf("%10.1x", xp->x_iptr);
-               printf("%5d", xp->x_count&0377);
-               printf("%5d", xp->x_ccount);
-               printf("\n");
-       }
-       free(xtext);
+       (void)printf(" FILEID IFLAG RDEV|SZ");
 }
 
 }
 
-doproc()
+int
+ufs_print(vp) 
+       struct vnode *vp;
 {
 {
-       struct proc *xproc, *aproc;
-       int nproc;
-       register struct proc *pp;
-       register loc, np;
-       struct pte apte;
-
-       nproc = getw(nl[SNPROC].n_value);
-       xproc = (struct proc *)calloc(nproc, sizeof (struct proc));
-       lseek(fc, (int)(aproc = (struct proc *)getw(nl[SPROC].n_value)), 0);
-       read(fc, xproc, nproc * sizeof (struct proc));
-       np = 0;
-       for (pp=xproc; pp < &xproc[nproc]; pp++)
-               if (pp->p_stat)
-                       np++;
-       if (totflg) {
-               printf("%3d/%3d processes\n", np, nproc);
-               return;
-       }
-       printf("%d/%d processes\n", np, nproc);
-       printf("   LOC    S    F POIP PRI      SIG  UID SLP TIM  CPU  NI   PGRP    PID   PPID    ADDR   RSS SRSS SIZE    WCHAN    LINK   TEXTP CLKT\n");
-       for (pp=xproc; pp<&xproc[nproc]; pp++) {
-               if (pp->p_stat==0 && allflg==0)
-                       continue;
-               printf("%8x", aproc + (pp - xproc));
-               printf(" %2d", pp->p_stat);
-               printf(" %4x", pp->p_flag & 0xffff);
-               printf(" %4d", pp->p_poip);
-               printf(" %3d", pp->p_pri);
-               printf(" %8x", pp->p_sig);
-               printf(" %4d", pp->p_uid);
-               printf(" %3d", pp->p_slptime);
-               printf(" %3d", pp->p_time);
-               printf(" %4d", pp->p_cpu&0377);
-               printf(" %3d", pp->p_nice);
-               printf(" %6d", pp->p_pgrp);
-               printf(" %6d", pp->p_pid);
-               printf(" %6d", pp->p_ppid);
-               if (kflg)
-                       pp->p_addr = (struct pte *)clear((int)pp->p_addr);
-               lseek(fc, (long)(Usrptma+btokmx(pp->p_addr)), 0);
-               read(fc, &apte, sizeof(apte));
-               printf(" %8x", ctob(apte.pg_pfnum+1) - sizeof(struct pte) * UPAGES);
-               printf(" %4x", pp->p_rssize);
-               printf(" %4x", pp->p_swrss);
-               printf(" %5x", pp->p_dsize+pp->p_ssize);
-               printf(" %7x", clear(pp->p_wchan));
-               printf(" %7x", clear(pp->p_link));
-               printf(" %7x", clear(pp->p_textp));
-               printf("    %u", pp->p_clktim);
-               printf("\n");
-       }
+       register int flag;
+       struct inode inode, *ip = &inode;
+       char flagbuf[16], *flags = flagbuf;
+       char *name;
+       mode_t type;
+
+       KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
+       flag = ip->i_flag;
+       if (flag & ILOCKED)
+               *flags++ = 'L';
+       if (flag & IWANT)
+               *flags++ = 'W';
+       if (flag & IRENAME)
+               *flags++ = 'R';
+       if (flag & IUPD)
+               *flags++ = 'U';
+       if (flag & IACC)
+               *flags++ = 'A';
+       if (flag & ICHG)
+               *flags++ = 'C';
+       if (flag & IMOD)
+               *flags++ = 'M';
+       if (flag & ISHLOCK)
+               *flags++ = 'S';
+       if (flag & IEXLOCK)
+               *flags++ = 'E';
+       if (flag & ILWAIT)
+               *flags++ = 'Z';
+       if (flag == 0)
+               *flags++ = '-';
+       *flags = '\0';
+
+       (void)printf(" %6d %5s", ip->i_number, flagbuf);
+       type = ip->i_mode & S_IFMT;
+       if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+               if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL))
+                       (void)printf("   %2d,%-2d", 
+                           major(ip->i_rdev), minor(ip->i_rdev));
+               else
+                       (void)printf(" %7s", name);
+       else
+               (void)printf(" %7qd", ip->i_size);
+       return (0);
 }
 
 }
 
-dotty()
+void
+nfs_header() 
 {
 {
-       struct tty dz_tty[64];
-       int ndz;
-       register struct tty *tp;
-       register char *mesg;
-
-       printf("1 cons\n");
-       lseek(fc, (long)nl[SKL].n_value, 0);
-       read(fc, dz_tty, sizeof(dz_tty[0]));
-       mesg = " # RAW CAN OUT   MODE    ADDR   DEL COL  STATE   PGRP DISC\n";
-       printf(mesg);
-       ttyprt(&dz_tty[0], 0);
-       if (nl[SNDZ].n_type == 0)
-               goto dh;
-       lseek(fc, (long)nl[SNDZ].n_value, 0);
-       read(fc, &ndz, sizeof(ndz));
-       printf("%d dz lines\n", ndz);
-       lseek(fc, (long)nl[SDZ].n_value, 0);
-       read(fc, dz_tty, sizeof(dz_tty));
-       for (tp = dz_tty; tp < &dz_tty[ndz]; tp++)
-               ttyprt(tp, tp - dz_tty);
-dh:
-       if (nl[SNDH].n_type == 0)
-               return;
-       lseek(fc, (long)nl[SNDH].n_value, 0);
-       read(fc, &ndz, sizeof(ndz));
-       printf("%d dh lines\n", ndz);
-       lseek(fc, (long)nl[SDH].n_value, 0);
-       read(fc, dz_tty, sizeof(dz_tty));
-       for (tp = dz_tty; tp < &dz_tty[ndz]; tp++)
-               ttyprt(tp, tp - dz_tty);
+       (void)printf(" FILEID NFLAG RDEV|SZ");
 }
 
 }
 
-ttyprt(atp, line)
-struct tty *atp;
+int
+nfs_print(vp) 
+       struct vnode *vp;
 {
 {
-       register struct tty *tp;
+       struct nfsnode nfsnode, *np = &nfsnode;
+       char flagbuf[16], *flags = flagbuf;
+       register int flag;
+       char *name;
+       mode_t type;
 
 
-       printf("%2d", line);
-       tp = atp;
-       switch (tp->t_line) {
+       KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
+       flag = np->n_flag;
+       if (flag & NFLUSHWANT)
+               *flags++ = 'W';
+       if (flag & NFLUSHINPROG)
+               *flags++ = 'P';
+       if (flag & NMODIFIED)
+               *flags++ = 'M';
+       if (flag & NWRITEERR)
+               *flags++ = 'E';
+       if (flag & NQNFSNONCACHE)
+               *flags++ = 'X';
+       if (flag & NQNFSWRITE)
+               *flags++ = 'O';
+       if (flag & NQNFSEVICTED)
+               *flags++ = 'G';
+       if (flag == 0)
+               *flags++ = '-';
+       *flags = '\0';
 
 
-       case NETLDISC:
-               if (tp->t_rec)
-                       printf("%4d%4d", 0, tp->t_inbuf);
+#define VT     np->n_vattr
+       (void)printf(" %6d %5s", VT.va_fileid, flagbuf);
+       type = VT.va_mode & S_IFMT;
+       if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode))
+               if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL))
+                       (void)printf("   %2d,%-2d", 
+                           major(VT.va_rdev), minor(VT.va_rdev));
                else
                else
-                       printf("%4d%4d", tp->t_inbuf, 0);
-               break;
-
-       default:
-               printf("%4d", tp->t_rawq.c_cc);
-               printf("%4d", tp->t_canq.c_cc);
-       }
-       printf("%4d", tp->t_outq.c_cc);
-       printf("%8.1o", tp->t_flags);
-       printf(" %8.1x", tp->t_addr);
-       printf("%3d", tp->t_delct);
-       printf("%4d ", tp->t_col);
-       putf(tp->t_state&TIMEOUT, 'T');
-       putf(tp->t_state&WOPEN, 'W');
-       putf(tp->t_state&ISOPEN, 'O');
-       putf(tp->t_state&CARR_ON, 'C');
-       putf(tp->t_state&BUSY, 'B');
-       putf(tp->t_state&ASLEEP, 'A');
-       putf(tp->t_state&XCLUDE, 'X');
+                       (void)printf(" %7s", name);
+       else
+               (void)printf(" %7qd", np->n_size);
+       return (0);
+}
+       
 /*
 /*
-       putf(tp->t_state&HUPCLS, 'H');
+ * Given a pointer to a mount structure in kernel space,
+ * read it in and return a usable pointer to it.
  */
  */
-       printf("%6d", tp->t_pgrp);
-       switch (tp->t_line) {
+struct mount *
+getmnt(maddr)
+       struct mount *maddr;
+{
+       static struct mtab {
+               struct mtab *next;
+               struct mount *maddr;
+               struct mount mount;
+       } *mhead = NULL;
+       register struct mtab *mt;
 
 
-       case NTTYDISC:
-               printf(" ntty");
-               break;
+       for (mt = mhead; mt != NULL; mt = mt->next)
+               if (maddr == mt->maddr)
+                       return (&mt->mount);
+       if ((mt = malloc(sizeof(struct mtab))) == NULL)
+               err(1, NULL);
+       KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table");
+       mt->maddr = maddr;
+       mt->next = mhead;
+       mhead = mt;
+       return (&mt->mount);
+}
+
+void
+mount_print(mp)
+       struct mount *mp;
+{
+       register int flags;
+       char *type;
 
 
-       case NETLDISC:
-               printf(" net");
+#define ST     mp->mnt_stat
+       (void)printf("*** MOUNT ");
+       switch (ST.f_type) {
+       case MOUNT_NONE:
+               type = "none";
+               break;
+       case MOUNT_UFS:
+               type = "ufs";
+               break;
+       case MOUNT_NFS:
+               type = "nfs";
                break;
                break;
+       case MOUNT_MFS:
+               type = "mfs";
+               break;
+       case MOUNT_PC:
+               type = "pc";
+               break;
+       default:
+               type = "unknown";
+               break;
+       }
+       (void)printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname);
+       if (flags = mp->mnt_flag) {
+               char *comma = "(";
+
+               putchar(' ');
+               /* user visable flags */
+               if (flags & MNT_RDONLY) {
+                       (void)printf("%srdonly", comma);
+                       flags &= ~MNT_RDONLY;
+                       comma = ",";
+               }
+               if (flags & MNT_SYNCHRONOUS) {
+                       (void)printf("%ssynchronous", comma);
+                       flags &= ~MNT_SYNCHRONOUS;
+                       comma = ",";
+               }
+               if (flags & MNT_NOEXEC) {
+                       (void)printf("%snoexec", comma);
+                       flags &= ~MNT_NOEXEC;
+                       comma = ",";
+               }
+               if (flags & MNT_NOSUID) {
+                       (void)printf("%snosuid", comma);
+                       flags &= ~MNT_NOSUID;
+                       comma = ",";
+               }
+               if (flags & MNT_NODEV) {
+                       (void)printf("%snodev", comma);
+                       flags &= ~MNT_NODEV;
+                       comma = ",";
+               }
+               if (flags & MNT_EXPORTED) {
+                       (void)printf("%sexport", comma);
+                       flags &= ~MNT_EXPORTED;
+                       comma = ",";
+               }
+               if (flags & MNT_EXRDONLY) {
+                       (void)printf("%sexrdonly", comma);
+                       flags &= ~MNT_EXRDONLY;
+                       comma = ",";
+               }
+               if (flags & MNT_LOCAL) {
+                       (void)printf("%slocal", comma);
+                       flags &= ~MNT_LOCAL;
+                       comma = ",";
+               }
+               if (flags & MNT_QUOTA) {
+                       (void)printf("%squota", comma);
+                       flags &= ~MNT_QUOTA;
+                       comma = ",";
+               }
+               /* filesystem control flags */
+               if (flags & MNT_UPDATE) {
+                       (void)printf("%supdate", comma);
+                       flags &= ~MNT_UPDATE;
+                       comma = ",";
+               }
+               if (flags & MNT_MLOCK) {
+                       (void)printf("%slock", comma);
+                       flags &= ~MNT_MLOCK;
+                       comma = ",";
+               }
+               if (flags & MNT_MWAIT) {
+                       (void)printf("%swait", comma);
+                       flags &= ~MNT_MWAIT;
+                       comma = ",";
+               }
+               if (flags & MNT_MPBUSY) {
+                       (void)printf("%sbusy", comma);
+                       flags &= ~MNT_MPBUSY;
+                       comma = ",";
+               }
+               if (flags & MNT_MPWANT) {
+                       (void)printf("%swant", comma);
+                       flags &= ~MNT_MPWANT;
+                       comma = ",";
+               }
+               if (flags & MNT_UNMOUNT) {
+                       (void)printf("%sunmount", comma);
+                       flags &= ~MNT_UNMOUNT;
+                       comma = ",";
+               }
+               if (flags)
+                       (void)printf("%sunknown_flags:%x", comma, flags);
+               (void)printf(")");
        }
        }
-       printf("\n");
+       (void)printf("\n");
+#undef ST
 }
 
 }
 
-dousr()
+struct e_vnode *
+loadvnodes(avnodes)
+       int *avnodes;
 {
 {
-       struct user U;
-       register i, j, *ip;
-
-       /* This wins only if PAGSIZ > sizeof (struct user) */
-       lseek(fc, ubase * NBPG, 0);
-       read(fc, &U, sizeof(U));
-       printf("pcb");
-       ip = (int *)&U.u_pcb;
-       while (ip < &U.u_arg[0]) {
-               if ((ip - (int *)&U.u_pcb) % 4 == 0)
-                       printf("\t");
-               printf("%x ", *ip++);
-               if ((ip - (int *)&U.u_pcb) % 4 == 0)
-                       printf("\n");
-       }
-       if ((ip - (int *)&U.u_pcb) % 4 != 0)
-               printf("\n");
-       printf("arg\t");
-       for (i=0; i<5; i++)
-               printf(" %.1x", U.u_arg[i]);
-       printf("\n");
-       for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
-               if (i%5==0)
-                       printf("\t");
-               printf("%9.1x", U.u_ssav[i]);
-               if (i%5==4)
-                       printf("\n");
-       }
-       if (i%5)
-               printf("\n");
-       printf("segflg\t%d\nerror %d\n", U.u_segflg, U.u_error);
-       printf("uids\t%d,%d,%d,%d\n", U.u_uid,U.u_gid,U.u_ruid,U.u_rgid);
-       printf("procp\t%.1x\n", U.u_procp);
-       printf("ap\t%.1x\n", U.u_ap);
-       printf("r_val?\t%.1x %.1x\n", U.u_r.r_val1, U.u_r.r_val2);
-       printf("base, count, offset %.1x %.1x %ld\n", U.u_base,
-               U.u_count, U.u_offset);
-       printf("cdir rdir %.1x %.1x\n", U.u_cdir, U.u_rdir);
-       printf("dbuf %.14s\n", U.u_dbuf);
-       printf("dirp %.1x\n", U.u_dirp);
-       printf("dent %d %.14s\n", U.u_dent.d_ino, U.u_dent.d_name);
-       printf("pdir %.1o\n", U.u_pdir);
-       printf("file\t");
-       for (i=0; i<10; i++)
-               printf("%9.1x", U.u_ofile[i]);
-       printf("\n\t");
-       for (i=10; i<NOFILE; i++)
-               printf("%9.1x", U.u_ofile[i]);
-       printf("\n");
-       printf("pofile\t");
-       for (i=0; i<10; i++)
-               printf("%9.1x", U.u_pofile[i]);
-       printf("\n\t");
-       for (i=10; i<NOFILE; i++)
-               printf("%9.1x", U.u_pofile[i]);
-       printf("\n");
-       printf("ssav");
-       for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
-               if (i%5==0)
-                       printf("\t");
-               printf("%9.1x", U.u_ssav[i]);
-               if (i%5==4)
-                       printf("\n");
+       int mib[2];
+       size_t copysize;
+       struct e_vnode *vnodebase;
+
+       if (memf != NULL) {
+               /*
+                * do it by hand
+                */
+               return (kinfo_vnodes(avnodes));
        }
        }
-       if (i%5)
-               printf("\n");
-       printf("sigs\t");
-       for (i=0; i<NSIG; i++)
-               printf("%.1x ", U.u_signal[i]);
-       printf("\n");
-       printf("code\t%.1x\n", U.u_code);
-       printf("ar0\t%.1x\n", U.u_ar0);
-       printf("prof\t%X %X %X %X\n", U.u_prof.pr_base, U.u_prof.pr_size,
-           U.u_prof.pr_off, U.u_prof.pr_scale);
-       printf("\neosys\t%d\n", U.u_eosys);
-       printf("sep\t%d\n", U.u_sep);
-       printf("ttyp\t%.1x\n", U.u_ttyp);
-       printf("ttyd\t%d,%d\n", major(U.u_ttyd), minor(U.u_ttyd));
-       printf("exdata\t");
-       ip = (int *)&U.u_exdata;
-       for (i = 0; i < 8; i++)
-               printf("%.1D ", *ip++);
-       printf("\n");
-       printf("comm %.14s\n", U.u_comm);
-       printf("start\t%D\n", U.u_start);
-       printf("acflag\t%D\n", U.u_acflag);
-       printf("fpflag\t%D\n", U.u_fpflag);
-       printf("cmask\t%D\n", U.u_cmask);
-       printf("sizes\t%.1x %.1x %.1x\n", U.u_tsize, U.u_dsize, U.u_ssize);
-       printf("vm\t");
-       ip = (int *)&U.u_vm;
-       for (i = 0; i < sizeof(U.u_vm)/sizeof(int); i++)
-               printf("%D ", ip[i]);
-       printf("\n");
-       ip = (int *)&U.u_cvm;
-       printf("cvm\t");
-       for (i = 0; i < sizeof(U.u_vm)/sizeof(int); i++)
-               printf("%D ", ip[i]);
-       printf("\n");
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_VNODE;
+       if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1)
+               err(1, "sysctl: KERN_VNODE");
+       if ((vnodebase = malloc(copysize)) == NULL)
+               err(1, NULL);
+       if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1)
+               err(1, "sysctl: KERN_VNODE");
+       if (copysize % sizeof(struct e_vnode))
+               errx(1, "vnode size mismatch");
+       *avnodes = copysize / sizeof(struct e_vnode);
+
+       return (vnodebase);
+}
+
 /*
 /*
-       i =  U.u_stack - &U;
-       while (U[++i] == 0);
-       i &= ~07;
-       while (i < 512) {
-               printf("%x ", 0140000+2*i);
-               for (j=0; j<8; j++)
-                       printf("%9x", U[i++]);
-               printf("\n");
-       }
-*/
+ * simulate what a running kernel does in in kinfo_vnode
+ */
+struct e_vnode *
+kinfo_vnodes(avnodes)
+       int *avnodes;
+{
+       int numvnodes;
+       struct mount *rootfs, *mp, mount;
+       char *vbuf, *evbuf, *bp;
+       struct vnode *vp, vnode;
+       int num;
+
+#define VPTRSZ  sizeof(struct vnode *)
+#define VNODESZ sizeof(struct vnode)
+
+       KGET(V_NUMV, numvnodes);
+       if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
+               err(1, NULL);
+       bp = vbuf;
+       evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
+       KGET(V_ROOTFS, rootfs);
+       mp = rootfs;
+       do {
+               KGET2(mp, &mount, sizeof(mount), "mount entry");
+               for (vp = mount.mnt_mounth; vp; vp = vnode.v_mountf) {
+                       KGET2(vp, &vnode, sizeof(vnode), "vnode");
+                       if ((bp + VPTRSZ + VNODESZ) > evbuf)
+                               /* XXX - should realloc */
+                               errx(1, "no more room for vnodes");
+                       memmove(bp, &vp, VPTRSZ);
+                       bp += VPTRSZ;
+                       memmove(bp, &vnode, VNODESZ);
+                       bp += VNODESZ;
+                       num++;
+               }
+               mp = mount.mnt_next;
+       } while (mp != rootfs);
+       *avnodes = num;
+       return ((struct e_vnode *)vbuf);
 }
 }
+       
+char hdr[]="  LINE RAW CAN OUT  HWT LWT     ADDR COL STATE  SESS  PGID DISC\n";
+int ttyspace = 128;
 
 
-oatoi(s)
-char *s;
+void
+ttymode()
 {
 {
-       register v;
+       struct tty *tty;
 
 
-       v = 0;
-       while (*s)
-               v = (v<<3) + *s++ - '0';
-       return(v);
+       if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL)
+               err(1, NULL);
+#ifndef hp300
+       (void)printf("1 console\n");
+       KGET(SCONS, *tty);
+       (void)printf(hdr);
+       ttyprt(&tty[0], 0);
+#endif
+#ifdef vax
+       if (nl[SNQD].n_type != 0) 
+               qdss();
+       if (nl[SNDZ].n_type != 0)
+               ttytype(tty, "dz", SDZ, SNDZ);
+       if (nl[SNDH].n_type != 0)
+               ttytype(tty, "dh", SDH, SNDH);
+       if (nl[SNDMF].n_type != 0)
+               ttytype(tty, "dmf", SDMF, SNDMF);
+       if (nl[SNDHU].n_type != 0)
+               ttytype(tty, "dhu", SDHU, SNDHU);
+       if (nl[SNDMZ].n_type != 0)
+               ttytype(tty, "dmz", SDMZ, SNDMZ);
+#endif
+#ifdef tahoe
+       if (nl[SNVX].n_type != 0)
+               ttytype(tty, "vx", SVX, SNVX);
+       if (nl[SNMP].n_type != 0)
+               ttytype(tty, "mp", SMP, SNMP);
+#endif
+#ifdef hp300
+       if (nl[SNITE].n_type != 0)
+               ttytype(tty, "ite", SITE, SNITE);
+       if (nl[SNDCA].n_type != 0)
+               ttytype(tty, "dca", SDCA, SNDCA);
+       if (nl[SNDCM].n_type != 0)
+               ttytype(tty, "dcm", SDCM, SNDCM);
+       if (nl[SNDCL].n_type != 0)
+               ttytype(tty, "dcl", SDCL, SNDCL);
+#endif
+#ifdef mips
+       if (nl[SNDC].n_type != 0)
+               ttytype(tty, "dc", SDC, SNDC);
+#endif
+       if (nl[SNPTY].n_type != 0)
+               ttytype(tty, "pty", SPTY, SNPTY);
 }
 
 }
 
-dofile()
+void
+ttytype(tty, name, type, number)
+       register struct tty *tty;
+       char *name;
+       int type, number;
 {
 {
-       int nfile;
-       struct file *xfile, *afile;
-       register struct file *fp;
-       register nf;
-       int loc;
-
-       nf = 0;
-       nfile = getw(nl[SNFILE].n_value);
-       xfile = (struct file *)calloc(nfile, sizeof (struct file));
-       lseek(fc, (int)(afile = (struct file *)getw(nl[SFIL].n_value)), 0);
-       read(fc, xfile, nfile * sizeof (struct file));
-       for (fp=xfile; fp < &xfile[nfile]; fp++)
-               if (fp->f_count)
-                       nf++;
-       if (totflg) {
-               printf("%3d/%3d files\n", nf, nfile);
+       register struct tty *tp;
+       int ntty;
+
+       if (tty == NULL)
                return;
                return;
+       KGET(number, ntty);
+       (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
+       if (ntty > ttyspace) {
+               ttyspace = ntty;
+               if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0)
+                       err(1, NULL);
        }
        }
-       printf("%d/%d open files\n", nf, nfile);
-       printf("   LOC   FLG  CNT   INO    OFFS\n");
-       for (fp=xfile,loc=nl[SFIL].n_value; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) {
-               if (fp->f_count==0)
-                       continue;
-               printf("%8x ", loc);
-               putf(fp->f_flag&FREAD, 'R');
-               putf(fp->f_flag&FWRITE, 'W');
-               putf(fp->f_flag&FPIPE, 'P');
-               printf("%4d", mask(fp->f_count));
-               printf("%9.1x", fp->f_inode);
-               printf("  %ld\n", fp->f_un.f_offset);
+       KGET1(type, tty, ntty * sizeof(struct tty), "tty structs");
+       (void)printf(hdr);
+       for (tp = tty; tp < &tty[ntty]; tp++)
+               ttyprt(tp, tp - tty);
+}
+
+struct {
+       int flag;
+       char val;
+} ttystates[] = {
+       { TS_WOPEN,     'W'},
+       { TS_ISOPEN,    'O'},
+       { TS_CARR_ON,   'C'},
+       { TS_TIMEOUT,   'T'},
+       { TS_FLUSH,     'F'},
+       { TS_BUSY,      'B'},
+       { TS_ASLEEP,    'A'},
+       { TS_XCLUDE,    'X'},
+       { TS_TTSTOP,    'S'},
+       { TS_TBLOCK,    'K'},
+       { TS_ASYNC,     'Y'},
+       { TS_BKSL,      'D'},
+       { TS_ERASE,     'E'},
+       { TS_LNCH,      'L'},
+       { TS_TYPEN,     'P'},
+       { TS_CNTTB,     'N'},
+       { 0,           '\0'},
+};
+
+void
+ttyprt(tp, line)
+       register struct tty *tp;
+       int line;
+{
+       register int i, j;
+       pid_t pgid;
+       char *name, state[20];
+
+       if (usenumflag || tp->t_dev == 0 ||
+          (name = devname(tp->t_dev, S_IFCHR)) == NULL)
+               (void)printf("%7d ", line); 
+       else
+               (void)printf("%7s ", name);
+       (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
+       (void)printf("%3d %4d %3d %8x %3d ", tp->t_outq.c_cc, 
+               tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col);
+       for (i = j = 0; ttystates[i].flag; i++)
+               if (tp->t_state&ttystates[i].flag)
+                       state[j++] = ttystates[i].val;
+       if (j == 0)
+               state[j++] = '-';
+       state[j] = '\0';
+       (void)printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE);
+       pgid = 0;
+       if (tp->t_pgrp != NULL)
+               KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
+       (void)printf("%6d ", pgid);
+       switch (tp->t_line) {
+       case TTYDISC:
+               (void)printf("term\n");
+               break;
+       case TABLDISC:
+               (void)printf("tab\n");
+               break;
+       case SLIPDISC:
+               (void)printf("slip\n");
+               break;
+       default:
+               (void)printf("%d\n", tp->t_line);
+               break;
        }
 }
 
        }
 }
 
-doswap()
+void
+filemode()
 {
 {
-       struct proc *proc;
-       int nproc;
-       struct text *xtext;
-       int ntext;
-       struct map *swapmap;
-       int nswapmap;
-       register struct proc *pp;
-       int nswap, used, tused, free;
-       register struct mapent *me;
-       register struct text *xp;
-
-       nproc = getw(nl[SNPROC].n_value);
-       proc = (struct proc *)calloc(nproc, sizeof (struct proc));
-       lseek(fc, getw(nl[SPROC].n_value), 0);
-       read(fc, proc, nproc * sizeof (struct proc));
-       nswapmap = getw(nl[SNSWAPMAP].n_value);
-       swapmap = (struct map *)calloc(nswapmap, sizeof (struct map));
-       lseek(fc, getw(nl[SWAPMAP].n_value), 0);
-       read(fc, swapmap, nswapmap * sizeof (struct map));
-       nswap = getw(nl[SNSWAP].n_value);
-       free = 0;
-       for (me = (struct mapent *)(swapmap+1);
-           me < (struct mapent *)&swapmap[nswapmap]; me++)
-               free += me->m_size;
-       ntext = getw(nl[SNTEXT].n_value);
-       xtext = (struct text *)calloc(ntext, sizeof (struct text));
-       lseek(fc, getw(nl[STEXT].n_value), 0);
-       read(fc, xtext, ntext * sizeof (struct text));
-       tused = 0;
-       for (xp = xtext; xp < &xtext[ntext]; xp++)
-               if (xp->x_iptr!=NULL)
-                       tused += xdsize(xp);
-       used = tused;
-       for (pp = proc; pp < &proc[nproc]; pp++) {
-               if (pp->p_stat == 0 || pp->p_stat == SZOMB)
-                       continue;
-               if (pp->p_flag & SSYS)
-                       continue;
-               used += up(pp->p_dsize) + up(pp->p_ssize);
-               if ((pp->p_flag&SLOAD) == 0)
-                       used += vusize(pp);
+       register struct file *fp;
+       struct file *addr;
+       char *buf, flagbuf[16], *fbp;
+       int len, maxfile, nfile;
+       static char *dtypes[] = { "???", "inode", "socket" };
+
+       KGET(FNL_MAXFILE, maxfile);
+       if (totalflag) {
+               KGET(FNL_NFILE, nfile);
+               (void)printf("%3d/%3d files\n", nfile, maxfile);
+               return;
        }
        }
-       /* a DMMAX/2 block goes to argmap */
-       if (totflg) {
-               printf("%3d/%3d 00k swap\n", used/2/100, (used+free)/2/100);
+       if (getfiles(&buf, &len) == -1)
                return;
                return;
+       /*
+        * Getfiles returns in malloc'd memory a pointer to the first file
+        * structure, and then an array of file structs (whose addresses are
+        * derivable from the previous entry).
+        */
+       addr = *((struct file **)buf);
+       fp = (struct file *)(buf + sizeof(struct file *));
+       nfile = (len - sizeof(struct file *)) / sizeof(struct file);
+       
+       (void)printf("%d/%d open files\n", nfile, maxfile);
+       (void)printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
+       for (; (char *)fp < buf + len; addr = fp->f_filef, fp++) {
+               if ((unsigned)fp->f_type > DTYPE_SOCKET)
+                       continue;
+               (void)printf("%x ", addr);
+               (void)printf("%-8.8s", dtypes[fp->f_type]);
+               fbp = flagbuf;
+               if (fp->f_flag & FREAD)
+                       *fbp++ = 'R';
+               if (fp->f_flag & FWRITE)
+                       *fbp++ = 'W';
+               if (fp->f_flag & FAPPEND)
+                       *fbp++ = 'A';
+#ifdef FSHLOCK /* currently gone */
+               if (fp->f_flag & FSHLOCK)
+                       *fbp++ = 'S';
+               if (fp->f_flag & FEXLOCK)
+                       *fbp++ = 'X';
+#endif
+               if (fp->f_flag & FASYNC)
+                       *fbp++ = 'I';
+               *fbp = '\0';
+               (void)printf("%6s  %3d", flagbuf, fp->f_count);
+               (void)printf("  %3d", fp->f_msgcount);
+               (void)printf("  %8.1x", fp->f_data);
+               if (fp->f_offset < 0)
+                       (void)printf("  %qx\n", fp->f_offset);
+               else
+                       (void)printf("  %qd\n", fp->f_offset);
        }
        }
-       printf("%d used (%d text), %d free, %d missing\n",
-           used/2, tused/2, free/2, (nswap - DMMAX/2 - (used + free))/2);
+       free(buf);
 }
 
 }
 
-up(size)
-       register int size;
+int
+getfiles(abuf, alen)
+       char **abuf;
+       int *alen;
 {
 {
-       register int i, block;
-
-       i = 0;
-       block = DMMIN;
-       while (i < size) {
-               i += block;
-               if (block < DMMAX)
-                       block *= 2;
+       size_t len;
+       int mib[2];
+       char *buf;
+
+       /*
+        * XXX
+        * Add emulation of KINFO_FILE here.
+        */
+       if (memf != NULL)
+               errx(1, "files on dead kernel, not implemented\n");
+
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_FILE;
+       if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
+               warn("sysctl: KERN_FILE");
+               return (-1);
        }
        }
-       return (i);
+       if ((buf = malloc(len)) == NULL)
+               err(1, NULL);
+       if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
+               warn("sysctl: KERN_FILE");
+               return (-1);
+       }
+       *abuf = buf;
+       *alen = len;
+       return (0);
 }
 
 }
 
-vusize(p)
-struct proc *p;
+/*
+ * swapmode is based on a program called swapinfo written
+ * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
+ */
+void
+swapmode()
 {
 {
-       register int tsz = p->p_tsize / NPTEPG;
+       char *header;
+       int hlen, nswap, nswdev, dmmax, nswapmap;
+       int s, e, div, i, avail, nfree, npfree, used;
+       struct swdevt *sw;
+       long blocksize, *perdev;
+       struct map *swapmap, *kswapmap;
+       struct mapent *mp;
 
 
-       return (clrnd(UPAGES + clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz));
-}
+       KGET(VM_NSWAP, nswap);
+       KGET(VM_NSWDEV, nswdev);
+       KGET(VM_DMMAX, dmmax);
+       KGET(VM_NSWAPMAP, nswapmap);
+       KGET(VM_SWAPMAP, kswapmap);     /* kernel `swapmap' is a pointer */
+       if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
+           (perdev = malloc(nswdev * sizeof(*perdev))) == NULL ||
+           (mp = malloc(nswapmap * sizeof(*mp))) == NULL)
+               err(1, "malloc");
+       KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt");
+       KGET2((long)kswapmap, mp, nswapmap * sizeof(*mp), "swapmap");
 
 
-xdsize(xp)
-struct text *xp;
-{
+       /* First entry in map is `struct map'; rest are mapent's. */
+       swapmap = (struct map *)mp;
+       if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap)
+               errx(1, "panic: nswapmap goof");
 
 
-       if (xp->x_flag & XPAGI)
-               return (clrnd(xp->x_size + ctopt(xp->x_size)));
-       return (xp->x_size);
-}
+       /* Count up swap space. */
+       nfree = 0;
+       memset(perdev, 0, nswdev * sizeof(*perdev));
+       for (mp++; mp->m_addr != 0; mp++) {
+               s = mp->m_addr;                 /* start of swap region */
+               e = mp->m_addr + mp->m_size;    /* end of region */
+               nfree += mp->m_size;
 
 
-dompx()
-{
-       register int i;
-       struct chan chans[NCHANS];
-       struct schan schans[NPORTS];
-
-       lseek(fc, (long)nl[SCHANS].n_value, 0);
-       read(fc, chans, sizeof chans);
-       lseek(fc, (long)nl[SSCHANS].n_value, 0);
-       read(fc, schans, sizeof schans);
-
-       printf("CHAN  FLAGS            INDEX     LINE  GROUP     FILE      TTYP      CTLX      PGRP    OTTYP     OLINE  DATQ      CTLY\n");
-       for (i = 0; i < NCHANS; i++) {
-               printf("%3d   ", i);
-               putf(chans[i].c_flags&INUSE, 'I');
-               putf(chans[i].c_flags&SIOCTL, 'S');
-               putf(chans[i].c_flags&XGRP, 'X');
-               putf(chans[i].c_flags&YGRP, 'Y');
-               putf(chans[i].c_flags&WCLOSE, 'W');
-               putf(chans[i].c_flags&ISGRP, 'i');
-               putf(chans[i].c_flags&BLOCK, 'B');
-               putf(chans[i].c_flags&EOTMARK, 'E');
-               putf(chans[i].c_flags&SIGBLK, 's');
-               putf(chans[i].c_flags&BLKMSG, 'b');
-               putf(chans[i].c_flags&ENAMSG, 'e');
-               putf(chans[i].c_flags&WFLUSH, 'w');
-               putf(chans[i].c_flags&NMBUF, 'N');
-               putf(chans[i].c_flags&PORT, 'P');
-               putf(chans[i].c_flags&ALT, 'A');
-               putf(chans[i].c_flags&FBLOCK, 'F');
-               printf("%8x  ", chans[i].c_index);
-               printf("%3d   ", chans[i].c_line);
-               printf("%8x  ", chans[i].c_group);
-               printf("%8x  ", chans[i].c_fy);
-               printf("%8x  ", chans[i].c_ttyp);
-               printf("%8x  ", chans[i].c_ctlx);
-               printf("%6d  ", chans[i].c_pgrp);
-               printf("%8x  ", chans[i].c_ottyp);
-               printf("%3d   ", chans[i].c_oline);
-               printf("%8x  ", chans[i].cx.datq);
-               printf("%8x\n", chans[i].c_ctly);
+               /*
+                * Swap space is split up among the configured disks.
+                * The first dmmax blocks of swap space some from the
+                * first disk, the next dmmax blocks from the next, 
+                * and so on.  The list of free space joins adjacent
+                * free blocks, ignoring device boundries.  If we want
+                * to keep track of this information per device, we'll
+                * just have to extract it ourselves.
+                */
+
+               /* calculate first device on which this falls */
+               i = (s / dmmax) % nswdev;
+               while (s < e) {         /* XXX this is inefficient */
+                       int bound = roundup(s+1, dmmax);
+
+                       if (bound > e)
+                               bound = e;
+                       perdev[i] += bound - s;
+                       if (++i >= nswdev)
+                               i = 0;
+                       s = bound;
+               }
+       }
+
+       header = getbsize(&hlen, &blocksize);
+       if (!totalflag)
+               (void)printf("%-10s %*s %10s %10s %10s\n",
+                   "Device", hlen, header, "Used", "Available", "Capacity");
+       div = blocksize / 512;
+       avail = npfree = 0;
+       for (i = 0; i < nswdev; i++) {
+               int xsize, xfree;
+
+               if (!totalflag)
+                       (void)printf("/dev/%-5s %*d ",
+                           devname(sw[i].sw_dev, S_IFBLK),
+                           hlen, sw[i].sw_nblks / div);
+
+               /*
+                * Don't report statistics for partitions which have not
+                * yet been activated via swapon(8).
+                */
+               if (!sw[i].sw_freed) {
+                       if (totalflag)
+                               continue;
+                       (void)printf(" *** not available for swapping ***\n");
+                       continue;
+               }
+               xsize = sw[i].sw_nblks;
+               xfree = perdev[i];
+               used = xsize - xfree;
+               npfree++;
+               avail += xsize;
+               if (totalflag)
+                       continue;
+               (void)printf("%10d %10d %7.0f%%\n", 
+                   used / div, xfree / div,
+                   (double)used / (double)xsize * 100.0);
        }
 
        }
 
-       printf("\nCHAN  FLAGS            INDEX     LINE  GROUP     FILE      TTYP      CTLX      PGRP\n");
-       for (i = 0; i < NPORTS; i++) {
-               printf("%3d  ", i);
-               putf(schans[i].c_flags&INUSE, 'I');
-               putf(schans[i].c_flags&SIOCTL, 'S');
-               putf(schans[i].c_flags&XGRP, 'X');
-               putf(schans[i].c_flags&YGRP, 'Y');
-               putf(schans[i].c_flags&WCLOSE, 'W');
-               putf(schans[i].c_flags&ISGRP, 'i');
-               putf(schans[i].c_flags&BLOCK, 'B');
-               putf(schans[i].c_flags&EOTMARK, 'E');
-               putf(schans[i].c_flags&SIGBLK, 's');
-               putf(schans[i].c_flags&BLKMSG, 'b');
-               putf(schans[i].c_flags&ENAMSG, 'e');
-               putf(schans[i].c_flags&WFLUSH, 'w');
-               putf(schans[i].c_flags&NMBUF, 'N');
-               putf(schans[i].c_flags&PORT, 'P');
-               putf(schans[i].c_flags&ALT, 'A');
-               putf(schans[i].c_flags&FBLOCK, 'F');
-               printf("%8x  ", schans[i].c_index);
-               printf("%3d   ", schans[i].c_line);
-               printf("%8x  ", schans[i].c_group);
-               printf("%8x  ", schans[i].c_fy);
-               printf("%8x  ", schans[i].c_ttyp);
-               printf("%8x  ", schans[i].c_ctlx);
-               printf("%6d\n", schans[i].c_pgrp);
+       /* 
+        * If only one partition has been set up via swapon(8), we don't
+        * need to bother with totals.
+        */
+       used = avail - nfree;
+       if (totalflag) {
+               (void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048);
+               return;
+       }
+       if (npfree > 1) {
+               (void)printf("%-10s %*d %10d %10d %7.0f%%\n",
+                   "Total", hlen, avail / div, used / div, nfree / div,
+                   (double)used / (double)avail * 100.0);
        }
 }
 
        }
 }
 
-dogroup()
+void
+usage()
 {
 {
-       register int i, j;
-       struct group *groups[NGROUPS];
-       struct group g;
-
-       lseek(fc, (long)nl[SGROUP].n_value, 0);
-       read(fc, groups, sizeof groups);
-       printf("GROUP STATE      INDEX     ROT  *GROUP    *INODE    *FILE     ROTM  DATQ\n");
-       for (i = 0; i < NGROUPS; i++) {
-               if (groups[i] == 0)
-                       continue;
-               lseek(fc, (long) groups[i], 0);
-               read(fc, &g, sizeof g);
-               printf("%3d   ", i);
-               printf("%8x  ", g.g_state);
-               printf("%8x  ", g.g_index);
-               printf("%3d  ", g.g_rot);
-               printf("%8x  ", g.g_group);
-               printf("%8x  ", g.g_inode);
-               printf("%8x  ", g.g_file);
-               printf("%3d   ", g.g_rotmask);
-               printf("%3d\n", g.g_datq);
-       }
+       (void)fprintf(stderr,
+           "usage: pstat -Tfnstv [system] [-M core] [-N system]\n");
+       exit(1);
 }
 }