4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / usr.sbin / pstat / pstat.c
index b0fae37..4b1d78f 100644 (file)
-/*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
- All rights reserved.\n";
-#endif not 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
 
 #ifndef lint
-static char sccsid[] = "@(#)pstat.c    5.9 (Berkeley) %G%";
-#endif not lint
-
-/*
- * Print system stuff
- */
-
-#define mask(x) (x&0377)
-#ifdef vax
-#define        clear(x) ((int)x&0x7fffffff)
-#endif
-#ifdef tahoe
-#define        clear(x) ((int)x&~0xc0000000)
-#endif
+static char sccsid[] = "@(#)pstat.c    8.1 (Berkeley) %G%";
+#endif /* not lint */
 
 #include <sys/param.h>
 
 #include <sys/param.h>
-#include <sys/dir.h>
-#define        KERNEL
-#include <sys/file.h>
-#undef KERNEL
-#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/ioctl.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 <machine/pte.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 
-char   *fcore  = "/dev/kmem";
-char   *fmem   = "/dev/mem";
-char   *fnlist = "/vmunix";
-int    fc, fm;
+#include "pathnames.h"
 
 struct nlist nl[] = {
 
 struct nlist nl[] = {
-#define        SINODE  0
-       { "_inode" },
-#define        STEXT   1
-       { "_text" },
-#define        SPROC   2
-       { "_proc" },
-#define        SCONS   3
+#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    4
-       { "_file" },
-#define        USRPTMA 5
-       { "_Usrptmap" },
-#define        USRPT   6
-       { "_usrpt" },
-#define        SWAPMAP 7
-       { "_swapmap" },
-#define        SNPROC  8
-       { "_nproc" },
-#define        SNTEXT  9
-       { "_ntext" },
-#define        SNFILE  10
-       { "_nfile" },
-#define        SNINODE 11
-       { "_ninode" },
-#define        SNSWAPMAP 12
-       { "_nswapmap" },
-#define        SPTY    13
+#define        SPTY    NLMANDATORY + 2
        { "_pt_tty" },
        { "_pt_tty" },
-#define        SDMMIN  14
-       { "_dmmin" },
-#define        SDMMAX  15
-       { "_dmmax" },
-#define        SNSWDEV 16
-       { "_nswdev" },
-#define        SSWDEVT 17
-       { "_swdevt" },
-#define        SYSMAP  18
-       { "_Sysmap" },
-#define        SNPTY   19
+#define        SNPTY   NLMANDATORY + 3
        { "_npty" },
        { "_npty" },
-#ifdef vax
-#define        SDZ     (SNPTY+1)
-       { "_dz_tty" },
-#define        SNDZ    (SNPTY+2)
-       { "_dz_cnt" },
-#define        SDMF    (SNPTY+3)
-       { "_dmf_tty" },
-#define        SNDMF   (SNPTY+4)
-       { "_ndmf" },
-#define        SDH     (SNPTY+5)
-       { "_dh11" },
-#define        SNDH    (SNPTY+6)
-       { "_ndh11" },
-#define        SDHU    (SNPTY+7)
-       { "_dhu_tty" },
-#define        SNDHU   (SNPTY+8)
-       { "_ndhu" },
-#define        SDMZ    (SNPTY+9)
-       { "_dmz_tty" },
-#define        SNDMZ   (SNPTY+10)
-       { "_ndmz" },
+
+#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
 #endif
-#ifdef tahoe
-#define        SVX     (SNPTY+1)
-       { "_vx_tty" },
-#define        SNVX    (SNPTY+2)
-       { "_nvx" },
+
+#ifdef mips
+#define SDC    (SNPTY+1)
+       { "_dc_tty" },
+#define SNDC   (SNPTY+2)
+       { "_dc_cnt" },
 #endif
 #endif
+
        { "" }
 };
 
        { "" }
 };
 
-int    inof;
-int    txtf;
-int    prcf;
-int    ttyf;
-int    usrf;
-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;
-u_long getw();
-off_t  mkphys();
+int    usenumflag;
+int    totalflag;
+char   *nlistf = NULL;
+char   *memf   = NULL;
+kvm_t  *kd;
+
+#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);                                             \
+       }
 
 
+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));
+
+int
 main(argc, argv)
 main(argc, argv)
-char **argv;
+       int argc;
+       char *argv[];
 {
 {
-       register char *argp;
-       int allflags;
-
-       argc--, argv++;
-       while (argc > 0 && **argv == '-') {
-               argp = *argv++;
-               argp++;
-               argc--;
-               while (*argp++)
-               switch (argp[-1]) {
+       extern char *optarg;
+       extern int optind;
+       int ch, i, quit, ret;
+       int fileflag, swapflag, ttyflag, vnodeflag;
+       char buf[_POSIX2_LINE_MAX];
 
 
-               case 'T':
-                       totflg++;
+       fileflag = swapflag = ttyflag = vnodeflag = 0;
+       while ((ch = getopt(argc, argv, "TM:N:finstv")) != EOF)
+               switch (ch) {
+               case 'f':
+                       fileflag = 1;
                        break;
                        break;
-
-               case 'a':
-                       allflg++;
+               case 'M':
+                       memf = optarg;
                        break;
                        break;
-
-               case 'i':
-                       inof++;
+               case 'N':
+                       nlistf = optarg;
                        break;
                        break;
-
-               case 'k':
-                       kflg++;
-                       fcore = fmem = "/vmcore";
+               case 'n':
+                       usenumflag = 1;
                        break;
                        break;
-
-               case 'x':
-                       txtf++;
+               case 's':
+                       swapflag = 1;
                        break;
                        break;
-
-               case 'p':
-                       prcf++;
+               case 'T':
+                       totalflag = 1;
                        break;
                        break;
-
                case 't':
                case 't':
-                       ttyf++;
+                       ttyflag = 1;
                        break;
                        break;
-
-               case 'u':
-                       if (argc == 0)
-                               break;
-                       argc--;
-                       usrf++;
-                       sscanf( *argv++, "%x", &ubase);
-                       break;
-
-               case 'f':
-                       filf++;
-                       break;
-               case 's':
-                       swpf++;
+               case 'v':
+               case 'i':               /* Backward compatibility. */
+                       vnodeflag = 1;
                        break;
                default:
                        usage();
                        break;
                default:
                        usage();
-                       exit(1);
                }
                }
+       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>1) {
-               fcore = fmem = argv[1];
-               kflg++;
-       }
-       if ((fc = open(fcore, 0)) < 0) {
-               printf("Can't find %s\n", fcore);
-               exit(1);
-       }
-       if ((fm = open(fmem, 0)) < 0) {
-               printf("Can't find %s\n", fmem);
-               exit(1);
-       }
-       if (argc>0)
-               fnlist = argv[0];
-       nlist(fnlist, nl);
-       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 (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
+               usage();
+       if (fileflag || totalflag)
+               filemode();
+       if (vnodeflag || totalflag)
+               vnodemode();
+       if (ttyflag)
+               ttymode();
+       if (swapflag || totalflag)
+               swapmode();
+       exit (0);
+}
+
+struct e_vnode {
+       struct vnode *avnode;
+       struct vnode vnode;
+};
+
+void
+vnodemode()
+{
+       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;
        }
        }
-       allflags = filf | totflg | inof | prcf | txtf | ttyf | usrf | swpf;
-       if (allflags == 0) {
-               printf("pstat: one or more of -[aixptfsu] is required\n");
-               exit(1);
+       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");
        }
        }
-       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();
+       free(e_vnodebase);
 }
 
 }
 
-usage()
+void
+vnode_header()
 {
 {
-
-       printf("usage: pstat -[aixptfs] [-u [ubase]] [system] [core]\n");
+       (void)printf("ADDR     TYP VFLAG  USE HOLD");
 }
 
 }
 
-doinode()
+void
+vnode_print(avnode, vp)
+       struct vnode *avnode;
+       struct vnode *vp;
 {
 {
-       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));
-       ainode = (struct inode *)getw(nl[SINODE].n_value);
-       if (ninode < 0 || ninode > 10000) {
-               fprintf(stderr, "number of inodes is preposterous (%d)\n",
-                       ninode);
-               return;
-       }
-       if (xinode == NULL) {
-               fprintf(stderr, "can't allocate memory for inode table\n");
-               return;
-       }
-       lseek(fc, mkphys((off_t)ainode), 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);
-               return;
-       }
-       printf("%d/%d active inodes\n", nin, ninode);
-printf("   LOC      FLAGS    CNT DEVICE  RDC WRC  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&ILOCKED, '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');
-               putf(ip->i_flag&ICHG, 'C');
-               putf(ip->i_flag&ISHLOCK, 'S');
-               putf(ip->i_flag&IEXLOCK, 'E');
-               putf(ip->i_flag&ILWAIT, 'Z');
-               printf("%4d", ip->i_count&0377);
-               printf("%4d,%3d", major(ip->i_dev), minor(ip->i_dev));
-               printf("%4d", ip->i_shlockc&0377);
-               printf("%4d", ip->i_exlockc&0377);
-               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_rdev), minor(ip->i_rdev));
-               else
-                       printf("%10ld", ip->i_size);
-               printf("\n");
+       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;
        }
        }
-       free(xinode);
+       /*
+        * 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);
+}
+
+void
+ufs_header() 
+{
+       (void)printf(" FILEID IFLAG RDEV|SZ");
 }
 
 }
 
-u_long
-getw(loc)
-       off_t loc;
+int
+ufs_print(vp) 
+       struct vnode *vp;
 {
 {
-       u_long word;
+       register int flag;
+       struct inode inode, *ip = &inode;
+       char flagbuf[16], *flags = flagbuf;
+       char *name;
+       mode_t type;
 
 
-       if (kflg)
-               loc = clear(loc);
-       lseek(fc, loc, 0);
-       read(fc, &word, sizeof (word));
-       return (word);
+       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);
 }
 
 }
 
-putf(v, n)
+void
+nfs_header() 
 {
 {
-       if (v)
-               printf("%c", n);
+       (void)printf(" FILEID NFLAG RDEV|SZ");
+}
+
+int
+nfs_print(vp) 
+       struct vnode *vp;
+{
+       struct nfsnode nfsnode, *np = &nfsnode;
+       char flagbuf[16], *flags = flagbuf;
+       register int flag;
+       char *name;
+       mode_t type;
+
+       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';
+
+#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
+                       (void)printf(" %7s", name);
        else
        else
-               printf(" ");
+               (void)printf(" %7qd", np->n_size);
+       return (0);
 }
 }
+       
+/*
+ * Given a pointer to a mount structure in kernel space,
+ * read it in and return a usable pointer to it.
+ */
+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;
 
 
-dotext()
+       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 struct text *xp;
-       int ntext;
-       struct text *xtext, *atext;
-       int ntx, ntxca;
-
-       ntx = ntxca = 0;
-       ntext = getw(nl[SNTEXT].n_value);
-       xtext = (struct text *)calloc(ntext, sizeof (struct text));
-       atext = (struct text *)getw(nl[STEXT].n_value);
-       if (ntext < 0 || ntext > 10000) {
-               fprintf(stderr, "number of texts is preposterous (%d)\n",
-                       ntext);
-               return;
-       }
-       if (xtext == NULL) {
-               fprintf(stderr, "can't allocate memory for text table\n");
-               return;
-       }
-       lseek(fc, mkphys((off_t)atext), 0);
-       read(fc, xtext, ntext * sizeof (struct text));
-       for (xp = xtext; xp < &xtext[ntext]; xp++) {
-               if (xp->x_iptr != NULL)
-                       ntxca++;
-               if (xp->x_count != 0)
-                       ntx++;
-       }
-       if (totflg) {
-               printf("%3d/%3d texts active, %3d used\n", ntx, ntext, ntxca);
-               return;
+       register int flags;
+       char *type;
+
+#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;
+       case MOUNT_MFS:
+               type = "mfs";
+               break;
+       case MOUNT_PC:
+               type = "pc";
+               break;
+       default:
+               type = "unknown";
+               break;
        }
        }
-       printf("%d/%d active texts, %d used\n", ntx, ntext, ntxca);
-       printf("\
-   LOC   FLAGS DADDR     CADDR  RSS SIZE     IPTR   CNT CCNT      FORW     BACK\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("%10x", 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("%10x", xp->x_forw);
-               printf("%9x", xp->x_back);
-               printf("\n");
+       (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(")");
        }
        }
-       free(xtext);
+       (void)printf("\n");
+#undef ST
 }
 
 }
 
-doproc()
+struct e_vnode *
+loadvnodes(avnodes)
+       int *avnodes;
 {
 {
-       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));
-       aproc = (struct proc *)getw(nl[SPROC].n_value);
-       if (nproc < 0 || nproc > 10000) {
-               fprintf(stderr, "number of procs is preposterous (%d)\n",
-                       nproc);
-               return;
-       }
-       if (xproc == NULL) {
-               fprintf(stderr, "can't allocate memory for proc table\n");
-               return;
-       }
-       lseek(fc, mkphys((off_t)aproc), 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\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);
-               if (pp->p_flag & SLOAD) {
-                       lseek(fc, (long)pp->p_addr, 0);
-                       read(fc, &apte, sizeof(apte));
-                       printf(" %8x", apte.pg_pfnum);
-               } else
-                       printf(" %8x", pp->p_swaddr);
-               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("\n");
+       int mib[2];
+       size_t copysize;
+       struct e_vnode *vnodebase;
+
+       if (memf != NULL) {
+               /*
+                * do it by hand
+                */
+               return (kinfo_vnodes(avnodes));
        }
        }
-       free(xproc);
+       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);
 }
 
 }
 
-static char mesg[] =
-" # RAW CAN OUT     MODE     ADDR DEL COL     STATE  PGRP DISC\n";
-static int ttyspace = 128;
-static struct tty *tty;
+/*
+ * 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)
 
 
-dotty()
+       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;
+
+void
+ttymode()
 {
 {
-       extern char *malloc();
+       struct tty *tty;
 
 
-       if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) {
-               printf("pstat: out of memory\n");
-               return;
-       }
-       printf("1 cons\n");
-       if (kflg)
-               nl[SCONS].n_value = clear(nl[SCONS].n_value);
-       lseek(fc, (long)nl[SCONS].n_value, 0);
-       read(fc, tty, sizeof(*tty));
-       printf(mesg);
+       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);
        ttyprt(&tty[0], 0);
+#endif
 #ifdef vax
 #ifdef vax
+       if (nl[SNQD].n_type != 0) 
+               qdss();
        if (nl[SNDZ].n_type != 0)
        if (nl[SNDZ].n_type != 0)
-               dottytype("dz", SDZ, SNDZ);
+               ttytype(tty, "dz", SDZ, SNDZ);
        if (nl[SNDH].n_type != 0)
        if (nl[SNDH].n_type != 0)
-               dottytype("dh", SDH, SNDH);
+               ttytype(tty, "dh", SDH, SNDH);
        if (nl[SNDMF].n_type != 0)
        if (nl[SNDMF].n_type != 0)
-               dottytype("dmf", SDMF, SNDMF);
+               ttytype(tty, "dmf", SDMF, SNDMF);
        if (nl[SNDHU].n_type != 0)
        if (nl[SNDHU].n_type != 0)
-               dottytype("dhu", SDHU, SNDHU);
+               ttytype(tty, "dhu", SDHU, SNDHU);
        if (nl[SNDMZ].n_type != 0)
        if (nl[SNDMZ].n_type != 0)
-               dottytype("dmz", SDMZ, SNDMZ);
+               ttytype(tty, "dmz", SDMZ, SNDMZ);
 #endif
 #ifdef tahoe
        if (nl[SNVX].n_type != 0)
 #endif
 #ifdef tahoe
        if (nl[SNVX].n_type != 0)
-               dottytype("vx", SVX, SNVX);
+               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)
 #endif
        if (nl[SNPTY].n_type != 0)
-               dottytype("pty", SPTY, SNPTY);
+               ttytype(tty, "pty", SPTY, SNPTY);
 }
 
 }
 
-dottytype(name, type, number)
-char *name;
+void
+ttytype(tty, name, type, number)
+       register struct tty *tty;
+       char *name;
+       int type, number;
 {
 {
-       int ntty;
        register struct tty *tp;
        register struct tty *tp;
-       extern char *realloc();
+       int ntty;
 
 
-       if (tty == (struct tty *)0)
+       if (tty == NULL)
                return;
                return;
-       if (kflg) {
-               nl[number].n_value = clear(nl[number].n_value);
-               nl[type].n_value = clear(nl[type].n_value);
-       }
-       lseek(fc, (long)nl[number].n_value, 0);
-       read(fc, &ntty, sizeof(ntty));
-       printf("%d %s lines\n", ntty, name);
+       KGET(number, ntty);
+       (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
        if (ntty > ttyspace) {
                ttyspace = ntty;
        if (ntty > ttyspace) {
                ttyspace = ntty;
-               if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
-                       printf("pstat: out of memory\n");
-                       return;
-               }
+               if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0)
+                       err(1, NULL);
        }
        }
-       lseek(fc, (long)nl[type].n_value, 0);
-       read(fc, tty, ntty * sizeof(struct tty));
-       printf(mesg);
+       KGET1(type, tty, ntty * sizeof(struct tty), "tty structs");
+       (void)printf(hdr);
        for (tp = tty; tp < &tty[ntty]; tp++)
                ttyprt(tp, tp - tty);
 }
 
        for (tp = tty; tp < &tty[ntty]; tp++)
                ttyprt(tp, tp - tty);
 }
 
-ttyprt(atp, line)
-struct tty *atp;
-{
-       register struct tty *tp;
-
-       printf("%2d", line);
-       tp = atp;
-       switch (tp->t_line) {
+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'},
+};
 
 
-#ifdef notdef
-       case NETLDISC:
-               if (tp->t_rec)
-                       printf("%4d%4d", 0, tp->t_inbuf);
-               else
-                       printf("%4d%4d", tp->t_inbuf, 0);
-               break;
-#endif
+void
+ttyprt(tp, line)
+       register struct tty *tp;
+       int line;
+{
+       register int i, j;
+       pid_t pgid;
+       char *name, state[20];
 
 
-       default:
-               printf("%4d%4d", tp->t_rawq.c_cc, tp->t_canq.c_cc);
-       }
-       printf("%4d %8x %8x%4d%4d", tp->t_outq.c_cc, tp->t_flags,
-               tp->t_addr, tp->t_delct, tp->t_col);
-       putf(tp->t_state&TS_TIMEOUT, 'T');
-       putf(tp->t_state&TS_WOPEN, 'W');
-       putf(tp->t_state&TS_ISOPEN, 'O');
-       putf(tp->t_state&TS_FLUSH, 'F');
-       putf(tp->t_state&TS_CARR_ON, 'C');
-       putf(tp->t_state&TS_BUSY, 'B');
-       putf(tp->t_state&TS_ASLEEP, 'A');
-       putf(tp->t_state&TS_XCLUDE, 'X');
-       putf(tp->t_state&TS_TTSTOP, 'S');
-       putf(tp->t_state&TS_HUPCLS, 'H');
-       printf("%6d", tp->t_pgrp);
+       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) {
        switch (tp->t_line) {
-
-       case OTTYDISC:
-               printf("\n");
+       case TTYDISC:
+               (void)printf("term\n");
                break;
                break;
-
-       case NTTYDISC:
-               printf(" ntty\n");
-               break;
-
-       case NETLDISC:
-               printf(" berknet\n");
-               break;
-
        case TABLDISC:
        case TABLDISC:
-               printf(" tab\n");
+               (void)printf("tab\n");
+               break;
+       case SLIPDISC:
+               (void)printf("slip\n");
                break;
                break;
-
        default:
        default:
-               printf(" %d\n", tp->t_line);
+               (void)printf("%d\n", tp->t_line);
+               break;
        }
 }
 
        }
 }
 
-dousr()
+void
+filemode()
 {
 {
-       struct user U;
-       register i, j, *ip;
-       register struct nameidata *nd = &U.u_nd;
-
-       /* This wins only if CLBYTES >= sizeof (struct user) */
-       lseek(fm, ubase * NBPG, 0);
-       read(fm, &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");
-       for (i=0; i<sizeof(U.u_arg)/sizeof(U.u_arg[0]); i++) {
-               if (i%5==0)
-                       printf("\t");
-               printf(" %.1x", U.u_arg[i]);
-               if (i%5==4)
-                       printf("\n");
-       }
-       if (i%5)
-               printf("\n");
-       printf("segflg\t%d\nerror %d\n", nd->ni_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", nd->ni_base,
-               nd->ni_count, nd->ni_offset);
-       printf("cdir rdir %.1x %.1x\n", U.u_cdir, U.u_rdir);
-       printf("dirp %.1x\n", nd->ni_dirp);
-       printf("dent %d %.14s\n", nd->ni_dent.d_ino, nd->ni_dent.d_name);
-       printf("pdir %.1o\n", nd->ni_pdir);
-       printf("file");
-       for (i=0; i<NOFILE; i++) {
-               if (i % 8 == 0)
-                       printf("\t");
-               printf("%9.1x", U.u_ofile[i]);
-               if (i % 8 == 7)
-                       printf("\n");
-       }
-       if (i % 8)
-               printf("\n");
-       printf("pofile");
-       for (i=0; i<NOFILE; i++) {
-               if (i % 8 == 0)
-                       printf("\t");
-               printf("%9.1x", U.u_pofile[i]);
-               if (i % 8 == 7)
-                       printf("\n");
-       }
-       if (i % 8)
-               printf("\n");
-       printf("ssave");
-       for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
-               if (i%5==0)
-                       printf("\t");
-               printf("%9.1x", U.u_ssave.val[i]);
-               if (i%5==4)
-                       printf("\n");
-       }
-       if (i%5)
-               printf("\n");
-       printf("sigs");
-       for (i=0; i<NSIG; i++) {
-               if (i % 8 == 0)
-                       printf("\t");
-               printf("%.1x ", U.u_signal[i]);
-               if (i % 8 == 7)
-                       printf("\n");
-       }
-       if (i % 8)
-               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("ttyp\t%.1x\n", U.u_ttyp);
-       printf("ttyd\t%d,%d\n", major(U.u_ttyd), minor(U.u_ttyd));
-       printf("comm %.14s\n", U.u_comm);
-       printf("start\t%D\n", U.u_start);
-       printf("acflag\t%D\n", U.u_acflag);
-       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("ru\t");
-       ip = (int *)&U.u_ru;
-       for (i = 0; i < sizeof(U.u_ru)/sizeof(int); i++)
-               printf("%D ", ip[i]);
-       printf("\n");
-       ip = (int *)&U.u_cru;
-       printf("cru\t");
-       for (i = 0; i < sizeof(U.u_cru)/sizeof(int); i++)
-               printf("%D ", ip[i]);
-       printf("\n");
-#ifdef notdef
-       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");
-       }
-#endif
-}
-
-oatoi(s)
-char *s;
-{
-       register v;
-
-       v = 0;
-       while (*s)
-               v = (v<<3) + *s++ - '0';
-       return(v);
-}
-
-dofile()
-{
-       int nfile;
-       struct file *xfile, *afile;
        register struct file *fp;
        register struct file *fp;
-       register nf;
-       int loc;
+       struct file *addr;
+       char *buf, flagbuf[16], *fbp;
+       int len, maxfile, nfile;
        static char *dtypes[] = { "???", "inode", "socket" };
 
        static char *dtypes[] = { "???", "inode", "socket" };
 
-       nf = 0;
-       nfile = getw(nl[SNFILE].n_value);
-       xfile = (struct file *)calloc(nfile, sizeof (struct file));
-       afile = (struct file *)getw(nl[SFIL].n_value);
-       if (nfile < 0 || nfile > 10000) {
-               fprintf(stderr, "number of files is preposterous (%d)\n",
-                       nfile);
+       KGET(FNL_MAXFILE, maxfile);
+       if (totalflag) {
+               KGET(FNL_NFILE, nfile);
+               (void)printf("%3d/%3d files\n", nfile, maxfile);
                return;
        }
                return;
        }
-       if (xfile == NULL) {
-               fprintf(stderr, "can't allocate memory for file table\n");
+       if (getfiles(&buf, &len) == -1)
                return;
                return;
-       }
-       lseek(fc, mkphys((off_t)afile), 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);
-               return;
-       }
-       printf("%d/%d open files\n", nf, nfile);
-       printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
-       for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) {
-               if (fp->f_count==0)
+       /*
+        * 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;
                        continue;
-               printf("%8x ", loc);
-               if (fp->f_type <= DTYPE_SOCKET)
-                       printf("%-8.8s", dtypes[fp->f_type]);
-               else
-                       printf("8d", fp->f_type);
-               putf(fp->f_flag&FREAD, 'R');
-               putf(fp->f_flag&FWRITE, 'W');
-               putf(fp->f_flag&FAPPEND, 'A');
-               putf(fp->f_flag&FSHLOCK, 'S');
-               putf(fp->f_flag&FEXLOCK, 'X');
-               putf(fp->f_flag&FASYNC, 'I');
-               printf("  %3d", mask(fp->f_count));
-               printf("  %3d", mask(fp->f_msgcount));
-               printf("  %8.1x", fp->f_data);
+               (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)
                if (fp->f_offset < 0)
-                       printf("  %x\n", fp->f_offset);
+                       (void)printf("  %qx\n", fp->f_offset);
                else
                else
-                       printf("  %ld\n", fp->f_offset);
-       }
-       free(xfile);
-}
-
-int dmmin, dmmax, nswdev;
-
-doswap()
-{
-       struct proc *proc;
-       int nproc;
-       struct text *xtext;
-       int ntext;
-       struct map *swapmap;
-       int nswapmap;
-       struct swdevt *swdevt, *sw;
-       register struct proc *pp;
-       int nswap, used, tused, free, waste;
-       int db, sb;
-       register struct mapent *me;
-       register struct text *xp;
-       int i, j;
-
-       nproc = getw(nl[SNPROC].n_value);
-       ntext = getw(nl[SNTEXT].n_value);
-       if (nproc < 0 || nproc > 10000 || ntext < 0 || ntext > 10000) {
-               fprintf(stderr, "number of procs/texts is preposterous (%d, %d)\n",
-                       nproc, ntext);
-               return;
-       }
-       proc = (struct proc *)calloc(nproc, sizeof (struct proc));
-       if (proc == NULL) {
-               fprintf(stderr, "can't allocate memory for proc table\n");
-               exit(1);
-       }
-       xtext = (struct text *)calloc(ntext, sizeof (struct text));
-       if (xtext == NULL) {
-               fprintf(stderr, "can't allocate memory for text table\n");
-               exit(1);
-       }
-       nswapmap = getw(nl[SNSWAPMAP].n_value);
-       swapmap = (struct map *)calloc(nswapmap, sizeof (struct map));
-       if (swapmap == NULL) {
-               fprintf(stderr, "can't allocate memory for swapmap\n");
-               exit(1);
-       }
-       nswdev = getw(nl[SNSWDEV].n_value);
-       swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt));
-       if (swdevt == NULL) {
-               fprintf(stderr, "can't allocate memory for swdevt table\n");
-               exit(1);
-       }
-       lseek(fc, mkphys((off_t)nl[SSWDEVT].n_value), L_SET);
-       read(fc, swdevt, nswdev * sizeof (struct swdevt));
-       lseek(fc, mkphys((off_t)getw(nl[SPROC].n_value)), 0);
-       read(fc, proc, nproc * sizeof (struct proc));
-       lseek(fc, mkphys((off_t)getw(nl[STEXT].n_value)), 0);
-       read(fc, xtext, ntext * sizeof (struct text));
-       lseek(fc, mkphys((off_t)getw(nl[SWAPMAP].n_value)), 0);
-       read(fc, swapmap, nswapmap * sizeof (struct map));
-       swapmap->m_name = "swap";
-       swapmap->m_limit = (struct mapent *)&swapmap[nswapmap];
-       dmmin = getw(nl[SDMMIN].n_value);
-       dmmax = getw(nl[SDMMAX].n_value);
-       nswap = 0;
-       for (sw = swdevt; sw < &swdevt[nswdev]; sw++)
-               if (sw->sw_freed)
-                       nswap += sw->sw_nblks;
-       free = 0;
-       for (me = (struct mapent *)(swapmap+1);
-           me < (struct mapent *)&swapmap[nswapmap]; me++)
-               free += me->m_size;
-       tused = 0;
-       for (xp = xtext; xp < &xtext[ntext]; xp++)
-               if (xp->x_iptr!=NULL) {
-                       tused += ctod(clrnd(xp->x_size));
-                       if (xp->x_flag & XPAGI)
-                               tused += ctod(clrnd(ctopt(xp->x_size)));
-               }
-       used = tused;
-       waste = 0;
-       for (pp = proc; pp < &proc[nproc]; pp++) {
-               if (pp->p_stat == 0 || pp->p_stat == SZOMB)
-                       continue;
-               if (pp->p_flag & SSYS)
-                       continue;
-               db = ctod(pp->p_dsize), sb = up(db);
-               used += sb;
-               waste += sb - db;
-               db = ctod(pp->p_ssize), sb = up(db);
-               used += sb;
-               waste += sb - db;
-               if ((pp->p_flag&SLOAD) == 0)
-                       used += ctod(vusize(pp));
+                       (void)printf("  %qd\n", fp->f_offset);
        }
        }
-       if (totflg) {
-#define        btok(x) ((x) / (1024 / DEV_BSIZE))
-               printf("%3d/%3d 00k swap\n",
-                   btok(used/100), btok((used+free)/100));
-               return;
-       }
-       printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n",
-           btok(used), btok(tused), btok(free), btok(waste),
-/* a dmmax/2 block goes to argmap */
-           btok(nswap - dmmax/2 - (used + free)));
-       printf("avail: ");
-       for (i = dmmax; i >= dmmin; i /= 2) {
-               j = 0;
-               while (rmalloc(swapmap, i) != 0)
-                       j++;
-               if (j) printf("%d*%dk ", j, btok(i));
-       }
-       free = 0;
-       for (me = (struct mapent *)(swapmap+1);
-           me < (struct mapent *)&swapmap[nswapmap]; me++)
-               free += me->m_size;
-       printf("%d*1k\n", btok(free));
+       free(buf);
 }
 
 }
 
-up(size)
-       register int size;
-{
-       register int i, block;
-
-       i = 0;
-       block = dmmin;
-       while (i < size) {
-               i += block;
-               if (block < dmmax)
-                       block *= 2;
-       }
-       return (i);
-}
-
-/*
- * Compute number of pages to be allocated to the u. area
- * and data and stack area page tables, which are stored on the
- * disk immediately after the u. area.
- */
-vusize(p)
-       register struct proc *p;
+int
+getfiles(abuf, alen)
+       char **abuf;
+       int *alen;
 {
 {
-       register int tsz = p->p_tsize / NPTEPG;
+       size_t len;
+       int mib[2];
+       char *buf;
 
        /*
 
        /*
-        * We do not need page table space on the disk for page
-        * table pages wholly containing text. 
+        * XXX
+        * Add emulation of KINFO_FILE here.
         */
         */
-       return (clrnd(UPAGES +
-           clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz));
-}
+       if (memf != NULL)
+               errx(1, "files on dead kernel, not implemented\n");
 
 
-/*
- * Allocate 'size' units from the given
- * map. Return the base of the allocated space.
- * In a map, the addresses are increasing and the
- * list is terminated by a 0 size.
- *
- * Algorithm is first-fit.
- *
- * This routine knows about the interleaving of the swapmap
- * and handles that.
- */
-long
-rmalloc(mp, size)
-       register struct map *mp;
-       long size;
-{
-       register struct mapent *ep = (struct mapent *)(mp+1);
-       register int addr;
-       register struct mapent *bp;
-       swblk_t first, rest;
-
-       if (size <= 0 || size > dmmax)
-               return (0);
-       /*
-        * Search for a piece of the resource map which has enough
-        * free space to accomodate the request.
-        */
-       for (bp = ep; bp->m_size; bp++) {
-               if (bp->m_size >= size) {
-                       /*
-                        * If allocating from swapmap,
-                        * then have to respect interleaving
-                        * boundaries.
-                        */
-                       if (nswdev > 1 &&
-                           (first = dmmax - bp->m_addr%dmmax) < bp->m_size) {
-                               if (bp->m_size - first < size)
-                                       continue;
-                               addr = bp->m_addr + first;
-                               rest = bp->m_size - first - size;
-                               bp->m_size = first;
-                               if (rest)
-                                       rmfree(mp, rest, addr+size);
-                               return (addr);
-                       }
-                       /*
-                        * Allocate from the map.
-                        * If there is no space left of the piece
-                        * we allocated from, move the rest of
-                        * the pieces to the left.
-                        */
-                       addr = bp->m_addr;
-                       bp->m_addr += size;
-                       if ((bp->m_size -= size) == 0) {
-                               do {
-                                       bp++;
-                                       (bp-1)->m_addr = bp->m_addr;
-                               } while ((bp-1)->m_size = bp->m_size);
-                       }
-                       if (addr % CLSIZE)
-                               return (0);
-                       return (addr);
-               }
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_FILE;
+       if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
+               warn("sysctl: KERN_FILE");
+               return (-1);
        }
        }
+       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);
 }
 
 /*
        return (0);
 }
 
 /*
- * Free the previously allocated space at addr
- * of size units into the specified map.
- * Sort addr into map and combine on
- * one or both ends if possible.
+ * swapmode is based on a program called swapinfo written
+ * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
  */
  */
-rmfree(mp, size, addr)
-       struct map *mp;
-       long size, addr;
+void
+swapmode()
 {
 {
-       struct mapent *firstbp;
-       register struct mapent *bp;
-       register int t;
+       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;
+
+       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");
+
+       /* 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");
+
+       /* 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;
 
 
-       /*
-        * Both address and size must be
-        * positive, or the protocol has broken down.
-        */
-       if (addr <= 0 || size <= 0)
-               goto badrmfree;
-       /*
-        * Locate the piece of the map which starts after the
-        * returned space (or the end of the map).
-        */
-       firstbp = bp = (struct mapent *)(mp + 1);
-       for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
-               continue;
-       /*
-        * If the piece on the left abuts us,
-        * then we should combine with it.
-        */
-       if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
-               /*
-                * Check no overlap (internal error).
-                */
-               if ((bp-1)->m_addr+(bp-1)->m_size > addr)
-                       goto badrmfree;
                /*
                /*
-                * Add into piece on the left by increasing its size.
+                * 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.
                 */
                 */
-               (bp-1)->m_size += size;
+
+               /* 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);
+
                /*
                /*
-                * If the combined piece abuts the piece on
-                * the right now, compress it in also,
-                * by shifting the remaining pieces of the map over.
+                * Don't report statistics for partitions which have not
+                * yet been activated via swapon(8).
                 */
                 */
-               if (bp->m_addr && addr+size >= bp->m_addr) {
-                       if (addr+size > bp->m_addr)
-                               goto badrmfree;
-                       (bp-1)->m_size += bp->m_size;
-                       while (bp->m_size) {
-                               bp++;
-                               (bp-1)->m_addr = bp->m_addr;
-                               (bp-1)->m_size = bp->m_size;
-                       }
+               if (!sw[i].sw_freed) {
+                       if (totalflag)
+                               continue;
+                       (void)printf(" *** not available for swapping ***\n");
+                       continue;
                }
                }
-               goto done;
+               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);
        }
        }
-       /*
-        * Don't abut on the left, check for abutting on
-        * the right.
+
+       /* 
+        * If only one partition has been set up via swapon(8), we don't
+        * need to bother with totals.
         */
         */
-       if (addr+size >= bp->m_addr && bp->m_size) {
-               if (addr+size > bp->m_addr)
-                       goto badrmfree;
-               bp->m_addr -= size;
-               bp->m_size += size;
-               goto done;
+       used = avail - nfree;
+       if (totalflag) {
+               (void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048);
+               return;
        }
        }
-       /*
-        * Don't abut at all.  Make a new entry
-        * and check for map overflow.
-        */
-       do {
-               t = bp->m_addr;
-               bp->m_addr = addr;
-               addr = t;
-               t = bp->m_size;
-               bp->m_size = size;
-               bp++;
-       } while (size = t);
-       /*
-        * Segment at bp is to be the delimiter;
-        * If there is not room for it 
-        * then the table is too full
-        * and we must discard something.
-        */
-       if (bp+1 > mp->m_limit) {
-               /*
-                * Back bp up to last available segment.
-                * which contains a segment already and must
-                * be made into the delimiter.
-                * Discard second to last entry,
-                * since it is presumably smaller than the last
-                * and move the last entry back one.
-                */
-               bp--;
-               printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
-                   (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
-               bp[-1] = bp[0];
-               bp[0].m_size = bp[0].m_addr = 0;
+       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);
        }
        }
-done:
-       return;
-badrmfree:
-       printf("bad rmfree\n");
 }
 }
-/*
- * "addr"  is a kern virt addr and does not correspond
- * To a phys addr after zipping out the high bit..
- * since it was valloc'd in the kernel.
- *
- * We return the phys addr by simulating kernel vm (/dev/kmem)
- * when we are reading a crash dump.
- */
-off_t
-mkphys(addr)
-       off_t addr;
+
+void
+usage()
 {
 {
-       register off_t o;
-
-       if (!kflg)
-               return(addr);
-       o = addr & PGOFSET;
-       addr >>= PGSHIFT;
-       addr &= PG_PFNUM;
-       addr *=  NBPW;
-       addr = getw(nl[SYSMAP].n_value + addr);
-       addr = ((addr & PG_PFNUM) << PGSHIFT) | o;
-       return(addr);
+       (void)fprintf(stderr,
+           "usage: pstat -Tfnstv [system] [-M core] [-N system]\n");
+       exit(1);
 }
 }