kinfo_proc.h gone, stuff moved to <sys/sysctl.h>
[unix-history] / usr / src / usr.bin / fstat / fstat.c
index cc5024b..6b4678a 100644 (file)
-/*
- * Copyright (c) 1987 Regents of the University of California.
+/*-
+ * Copyright (c) 1988 The Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1987 Regents of the University of California.\n\
+"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)fstat.c    5.15 (Berkeley) %G%";
+static char sccsid[] = "@(#)fstat.c    5.44 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-/*
- *  fstat 
- */
-#include <machine/pte.h>
-
 #include <sys/param.h>
 #include <sys/param.h>
-#include <sys/dir.h>
-#include <sys/user.h>
+#include <sys/time.h>
 #include <sys/proc.h>
 #include <sys/proc.h>
-#include <sys/text.h>
+#include <sys/user.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/inode.h>
+#include <sys/vnode.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
 #include <sys/unpcb.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
 #include <sys/unpcb.h>
-#include <sys/vmmac.h>
+#include <sys/sysctl.h>
+#include <sys/filedesc.h>
 #define        KERNEL
 #include <sys/file.h>
 #define        KERNEL
 #include <sys/file.h>
-#undef KERNEL
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#undef KERNEL
+#define NFS
+#include <sys/mount.h>
+#include <nfs/nfsv2.h>
+#include <nfs/rpcv2.h>
+#include <nfs/nfs.h>
+#include <nfs/nfsnode.h>
+#undef NFS
+
 #include <net/route.h>
 #include <netinet/in.h>
 #include <net/route.h>
 #include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_pcb.h>
-#include <stdio.h>
+
 #include <ctype.h>
 #include <ctype.h>
+#include <errno.h>
+#include <kvm.h>
 #include <nlist.h>
 #include <nlist.h>
+#include <paths.h>
 #include <pwd.h>
 #include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 
-#ifdef ULTRIX
-               /* UFS -> GFS */
-#    define    inode   gnode
-#    define    x_iptr  x_gptr
-#    define    i_dev   g_dev
-#    define    i_number g_number
-#    define    i_mode  g_mode
-#    define    i_size  g_size
-#endif
-
-#define        N_KMEM  "/dev/kmem"
-#define        N_MEM   "/dev/mem"
-#define        N_SWAP  "/dev/drum"
-#define        N_UNIX  "/vmunix"
-
-#define        TEXT    -2
-#define        WD      -1
+#define        TEXT    -1
+#define        CDIR    -2
+#define        RDIR    -3
+#define        TRACE   -4
 
 typedef struct devs {
 
 typedef struct devs {
-       struct devs *next;
-       dev_t dev;
-       int inum;
-       char *name;
+       struct  devs *next;
+       long    fsid;
+       ino_t   ino;
+       char    *name;
 } DEVS;
 DEVS *devs;
 
 } DEVS;
 DEVS *devs;
 
-static struct nlist nl[] = {
-       { "_proc" },
-#define        X_PROC          0
-       { "_Usrptmap" },
-#define        X_USRPTMA       1
-       { "_nproc" },
-#define        X_NPROC         2
-       { "_usrpt" },
-#define        X_USRPT         3
+struct  filestat {
+       long    fsid;
+       long    fileid;
+       mode_t  mode;
+       u_long  size;
+       dev_t   rdev;
+};
+
+#ifdef notdef
+struct nlist nl[] = {
        { "" },
 };
        { "" },
 };
+#endif
 
 
-struct proc *mproc;
-struct pte *Usrptma, *usrpt;
+int    fsflg,  /* show files on same filesystem as file(s) argument */
+       pflg,   /* show files open by a particular pid */
+       uflg;   /* show files open by a particular (effective) user */
+int    checkfile; /* true if restricting to particular files or filesystems */
+int    nflg;   /* (numerical) display f.s. and rdev as dev_t */
+int    vflg;   /* display errors in locating kernel data objects etc... */
+
+#define dprintf        if (vflg) fprintf
+
+struct file **ofiles;  /* buffer of pointers to file structures */
+int maxfiles;
+#define ALLOC_OFILES(d)        \
+       if ((d) > maxfiles) { \
+               free(ofiles); \
+               ofiles = malloc((d) * sizeof(struct file *)); \
+               if (ofiles == NULL) { \
+                       fprintf(stderr, "fstat: %s\n", strerror(errno)); \
+                       exit(1); \
+               } \
+               maxfiles = (d); \
+       }
 
 
-union {
-       struct user user;
-       char upages[UPAGES][NBPG];
-} user;
+/*
+ * a kvm_read that returns true if everything is read 
+ */
+#define KVM_READ(kaddr, paddr, len) \
+       (kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (len))
 
 
-extern int errno;
-static int fflg, vflg;
-static int kmem, mem, nproc, swap;
-static char *uname;
+kvm_t *kd;
 
 
-off_t lseek();
+int ufs_filestat(), nfs_filestat();
+void dofiles(), getinetproto(), socktrans();
+void usage(), vtrans();
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
@@ -114,36 +125,52 @@ main(argc, argv)
        extern char *optarg;
        extern int optind;
        register struct passwd *passwd;
        extern char *optarg;
        extern int optind;
        register struct passwd *passwd;
-       register int pflg, pid, uflg, uid;
-       int ch, size;
-       struct passwd *getpwnam(), *getpwuid();
-       long lgetw();
-       char *malloc();
-
-       pflg = uflg = 0;
-       while ((ch = getopt(argc, argv, "p:u:v")) != EOF)
+       struct kinfo_proc *p, *plast;
+       int arg, ch, what;
+       char *memf, *nlistf;
+       int cnt;
+
+       arg = 0;
+       what = KERN_PROC_ALL;
+       nlistf = memf = NULL;
+       while ((ch = getopt(argc, argv, "fnp:u:vNM")) != EOF)
                switch((char)ch) {
                switch((char)ch) {
+               case 'f':
+                       fsflg = 1;
+                       break;
+               case 'M':
+                       memf = optarg;
+                       break;
+               case 'N':
+                       nlistf = optarg;
+                       break;
+               case 'n':
+                       nflg = 1;
+                       break;
                case 'p':
                        if (pflg++)
                                usage();
                        if (!isdigit(*optarg)) {
                case 'p':
                        if (pflg++)
                                usage();
                        if (!isdigit(*optarg)) {
-                               fputs("fstat: -p option requires a process id.\n", stderr);
+                               fprintf(stderr,
+                                   "fstat: -p requires a process id\n");
                                usage();
                        }
                                usage();
                        }
-                       pid = atoi(optarg);
+                       what = KERN_PROC_PID;
+                       arg = atoi(optarg);
                        break;
                case 'u':
                        if (uflg++)
                                usage();
                        if (!(passwd = getpwnam(optarg))) {
                        break;
                case 'u':
                        if (uflg++)
                                usage();
                        if (!(passwd = getpwnam(optarg))) {
-                               fprintf(stderr, "%s: unknown uid\n", optarg);
+                               fprintf(stderr, "%s: unknown uid\n",
+                                   optarg);
                                exit(1);
                        }
                                exit(1);
                        }
-                       uid = passwd->pw_uid;
-                       uname = passwd->pw_name;
+                       what = KERN_PROC_UID;
+                       arg = passwd->pw_uid;
                        break;
                        break;
-               case 'v':       /* undocumented: print read error messages */
-                       vflg++;
+               case 'v':
+                       vflg = 1;
                        break;
                case '?':
                default:
                        break;
                case '?':
                default:
@@ -153,209 +180,356 @@ main(argc, argv)
        if (*(argv += optind)) {
                for (; *argv; ++argv) {
                        if (getfname(*argv))
        if (*(argv += optind)) {
                for (; *argv; ++argv) {
                        if (getfname(*argv))
-                               fflg = 1;
+                               checkfile = 1;
                }
                }
-               if (!fflg)      /* file(s) specified, but none accessable */
+               if (!checkfile) /* file(s) specified, but none accessable */
+                       exit(1);
+       }
+
+       ALLOC_OFILES(256);      /* reserve space for file pointers */
+
+       if (fsflg && !checkfile) {      
+               /* -f with no files means use wd */
+               if (getfname(".") == 0)
                        exit(1);
                        exit(1);
+               checkfile = 1;
        }
 
        }
 
-       openfiles();
+       /*
+        * Discard setgid privileges if not the running kernel so that bad
+        * guys can't print interesting stuff from kernel memory.
+        */
+       if (nlistf != NULL || memf != NULL)
+               setgid(getgid());
 
 
-       if (nlist(N_UNIX, nl) == -1 || !nl[0].n_type) {
-               fprintf(stderr, "%s: No namelist\n", N_UNIX);
+       if ((kd = kvm_open(nlistf, memf, NULL, O_RDONLY, NULL)) == NULL) {
+               fprintf(stderr, "fstat: %s\n", kvm_geterr(kd));
+               exit(1);
+       }
+#ifdef notdef
+       if (kvm_nlist(kd, nl) != 0) {
+               fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr(kd));
                exit(1);
        }
                exit(1);
        }
-       Usrptma = (struct pte *)nl[X_USRPTMA].n_value;
-       usrpt = (struct pte *) nl[X_USRPT].n_value;
-       nproc = (int)lgetw((off_t)nl[X_NPROC].n_value);
-
-       (void)lseek(kmem, lgetw((off_t)nl[X_PROC].n_value), L_SET);
-       size = nproc * sizeof(struct proc);
-       if ((mproc = (struct proc *)malloc((u_int)size)) == NULL) {
-               fprintf(stderr, "fstat: out of space.\n");
+#endif
+       if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) {
+               fprintf(stderr, "fstat: %s\n", kvm_geterr(kd));
                exit(1);
        }
                exit(1);
        }
-       if (read(kmem, (char *)mproc, size) != size)
-               rerr1("proc table", N_KMEM);
+       if (nflg)
+               printf("%s",
+"USER     CMD          PID   FD  DEV    INUM       MODE SZ|DV");
+       else
+               printf("%s",
+"USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV");
+       if (checkfile && fsflg == 0)
+               printf(" NAME\n");
+       else
+               putchar('\n');
 
 
-       printf("USER\t CMD\t      PID    FD\tDEVICE\tINODE\t  SIZE TYPE%s\n",
-           fflg ? " NAME" : "");
-       for (; nproc--; ++mproc) {
-               if (mproc->p_stat == 0)
-                       continue;
-               if (pflg && mproc->p_pid != pid)
+       for (plast = &p[cnt]; p < plast; ++p) {
+               if (p->kp_proc.p_stat == SZOMB)
                        continue;
                        continue;
-               if (uflg)  {
-                       if (mproc->p_uid != uid)
-                               continue;
-               }
-               else
-                       uname = (passwd = getpwuid(mproc->p_uid)) ?
-                           passwd->pw_name : "unknown";
-               if (mproc->p_stat != SZOMB && getu() == 0)
-                       continue;
-               dotext();
-               readf();
+               dofiles(p);
        }
        exit(0);
 }
 
        }
        exit(0);
 }
 
-static
-getu()
-{
-       struct pte *pteaddr, apte;
-       struct pte arguutl[UPAGES+CLSIZE];
-       register int i;
-       int ncl;
-
-       if ((mproc->p_flag & SLOAD) == 0) {
-               if (swap < 0)
-                       return(0);
-               (void)lseek(swap, (off_t)dtob(mproc->p_swaddr), L_SET);
-               if (read(swap, (char *)&user.user, sizeof(struct user))
-                   != sizeof(struct user)) {
-                       fprintf(stderr, "fstat: can't read u for pid %d from %s\n", mproc->p_pid, N_SWAP);
-                       return(0);
-               }
-               return(1);
+char   *Uname, *Comm;
+int    Pid;
+
+#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
+       switch(i) { \
+       case TEXT: \
+               printf(" text"); \
+               break; \
+       case CDIR: \
+               printf("   wd"); \
+               break; \
+       case RDIR: \
+               printf(" root"); \
+               break; \
+       case TRACE: \
+               printf("   tr"); \
+               break; \
+       default: \
+               printf(" %4d", i); \
+               break; \
        }
        }
-       pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
-       (void)lseek(kmem, (off_t)pteaddr, L_SET);
-       if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
-               printf("fstat: can't read indir pte to get u for pid %d from %s\n", mproc->p_pid, N_SWAP);
-               return(0);
-       }
-       (void)lseek(mem, (off_t)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE)
-           * sizeof(struct pte), L_SET);
-       if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
-               printf("fstat: can't read page table for u of pid %d from %s\n", mproc->p_pid, N_KMEM);
-               return(0);
+
+/*
+ * print open files attributed to this process
+ */
+void
+dofiles(kp)
+       struct kinfo_proc *kp;
+{
+       int i, last;
+       struct file file;
+       struct filedesc0 filed0;
+#define        filed   filed0.fd_fd
+       struct proc *p = &kp->kp_proc;
+       struct eproc *ep = &kp->kp_eproc;
+
+       extern char *user_from_uid();
+
+       Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
+       Pid = p->p_pid;
+       Comm = p->p_comm;
+
+       if (p->p_fd == NULL)
+               return;
+       if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) {
+               dprintf(stderr, "can't read filedesc at %x for pid %d\n",
+                       p->p_fd, Pid);
+               return;
        }
        }
-       ncl = (sizeof(struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
-       while (--ncl >= 0) {
-               i = ncl * CLSIZE;
-               (void)lseek(mem, (off_t)ctob(arguutl[CLSIZE+i].pg_pfnum), L_SET);
-               if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
-                       printf("fstat: can't read page %u of u of pid %d from %s\n", arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, N_MEM);
-                       return(0);
+       /*
+        * root directory vnode, if one
+        */
+       if (filed.fd_rdir)
+               vtrans(filed.fd_rdir, RDIR);
+       /*
+        * current working directory vnode
+        */
+       vtrans(filed.fd_cdir, CDIR);
+       /*
+        * ktrace vnode, if one
+        */
+       if (p->p_tracep)
+               vtrans(p->p_tracep, TRACE);
+       /*
+        * open files
+        */
+#define FPSIZE (sizeof (struct file *))
+       ALLOC_OFILES(filed.fd_lastfile+1);
+       if (filed.fd_nfiles > NDFILE) {
+               if (!KVM_READ(filed.fd_ofiles, ofiles,
+                   (filed.fd_lastfile+1) * FPSIZE)) {
+                       dprintf(stderr,
+                           "can't read file structures at %x for pid %d\n",
+                           filed.fd_ofiles, Pid);
+                       return;
+               }
+       } else
+               bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE);
+       for (i = 0; i <= filed.fd_lastfile; i++) {
+               if (ofiles[i] == NULL)
+                       continue;
+               if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
+                       dprintf(stderr, "can't read file %d at %x for pid %d\n",
+                               i, ofiles[i], Pid);
+                       continue;
+               }
+               if (file.f_type == DTYPE_VNODE)
+                       vtrans((struct vnode *)file.f_data, i);
+               else if (file.f_type == DTYPE_SOCKET) {
+                       if (checkfile == 0)
+                               socktrans((struct socket *)file.f_data, i);
+               }
+               else {
+                       dprintf(stderr, 
+                               "unknown file type %d for file %d of pid %d\n",
+                               file.f_type, i, Pid);
                }
        }
                }
        }
-       return(1);
 }
 
 }
 
-static
-dotext()
+void
+vtrans(vp, i)
+       struct vnode *vp;
+       int i;
 {
 {
-       struct text text;
-
-       (void)lseek(kmem, (off_t)mproc->p_textp, L_SET);
-       if (read(kmem, (char *) &text, sizeof(text)) != sizeof(text)) {
-               rerr1("text table", N_KMEM);
+       extern char *devname();
+       struct vnode vn;
+       struct filestat fst;
+       char mode[15];
+       char *badtype = NULL, *filename, *getmnton();
+
+       filename = badtype = NULL;
+       if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
+               dprintf(stderr, "can't read vnode at %x for pid %d\n",
+                       vp, Pid);
                return;
        }
                return;
        }
-       if (text.x_flag)
-               itrans(DTYPE_INODE, text.x_iptr, TEXT);
-}
+       if (vn.v_type == VNON || vn.v_tag == VT_NON)
+               badtype = "none";
+       else if (vn.v_type == VBAD)
+               badtype = "bad";
+       else
+               switch (vn.v_tag) {
+               case VT_UFS:
+                       if (!ufs_filestat(&vn, &fst))
+                               badtype = "error";
+                       break;
+               case VT_MFS:
+                       if (!ufs_filestat(&vn, &fst))
+                               badtype = "error";
+                       break;
+               case VT_NFS:
+                       if (!nfs_filestat(&vn, &fst))
+                               badtype = "error";
+                       break;
+               default: {
+                       static char unknown[10];
+                       sprintf(badtype = unknown, "?(%x)", vn.v_tag);
+                       break;;
+               }
+       }
+       if (checkfile) {
+               int fsmatch = 0;
+               register DEVS *d;
 
 
-static
-itrans(ftype, g, fno)
-       int ftype, fno;
-       struct inode *g;                /* if ftype is inode */
-{
-       struct inode inode;
-       dev_t idev;
-       char *comm, *itype();
-       char *name = (char *)NULL;      /* set by devmatch() on a match */
-
-       if (g || fflg) {
-               (void)lseek(kmem, (off_t)g, L_SET);
-               if (read(kmem, (char *)&inode, sizeof(inode)) != sizeof(inode)) {
-                       rerr2(errno, (int)g, "inode");
+               if (badtype)
                        return;
                        return;
-               }
-               idev = inode.i_dev;
-               if (fflg && !devmatch(idev, inode.i_number, &name))
+               for (d = devs; d != NULL; d = d->next)
+                       if (d->fsid == fst.fsid) {
+                               fsmatch = 1;
+                               if (d->ino == fst.fileid) {
+                                       filename = d->name;
+                                       break;
+                               }
+                       }
+               if (fsmatch == 0 || (filename == NULL && fsflg == 0))
                        return;
        }
                        return;
        }
-       if (mproc->p_pid == 0)
-               comm = "swapper";
-       else if (mproc->p_pid == 2)
-               comm = "pagedaemon";
+       PREFIX(i);
+       if (badtype) {
+               (void)printf(" -         -  %10s    -\n", badtype);
+               return;
+       }
+       if (nflg)
+               (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
        else
        else
-               comm = user.user.u_comm;
-       printf("%-8.8s %-10.10s %5d  ", uname, comm, mproc->p_pid);
-
-       switch(fno) {
-       case WD:
-               printf("  wd"); break;
-       case TEXT:
-               printf("text"); break;
+               (void)printf(" %-8s", getmnton(vn.v_mount));
+       if (nflg)
+               (void)sprintf(mode, "%o", fst.mode);
+       else
+               strmode(fst.mode, mode);
+       (void)printf(" %6d %10s", fst.fileid, mode);
+       switch (vn.v_type) {
+       case VBLK:
+       case VCHR: {
+               char *name;
+
+               if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? 
+                   S_IFCHR : S_IFBLK)) == NULL))
+                       printf("  %2d,%-2d", major(fst.rdev), minor(fst.rdev));
+               else
+                       printf(" %6s", name);
+               break;
+       }
        default:
        default:
-               printf("%4d", fno);
+               printf(" %6d", fst.size);
        }
        }
+       if (filename && !fsflg)
+               printf(" %s", filename);
+               
+       putchar('\n');
+}
 
 
-       if (g == 0) {
-               printf("* (deallocated)\n");
-               return;
+int
+ufs_filestat(vp, fsp)
+       struct vnode *vp;
+       struct filestat *fsp;
+{
+       struct inode inode;
+
+       if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
+               dprintf(stderr, "can't read inode at %x for pid %d\n",
+                       VTOI(vp), Pid);
+               return 0;
        }
        }
+       fsp->fsid = inode.i_dev & 0xffff;
+       fsp->fileid = (long)inode.i_number;
+       fsp->mode = (mode_t)inode.i_mode;
+       fsp->size = (u_long)inode.i_size;
+       fsp->rdev = inode.i_rdev;
 
 
-       switch(ftype) {
-       case DTYPE_INODE:
-               printf("\t%2d, %2d\t%5lu\t",
-                   major(inode.i_dev),
-                   minor(inode.i_dev), inode.i_number
-               );
-               switch(inode.i_mode & IFMT) {
-               case    IFSOCK:
-                       printf("     0\t");
-                       break;
-               case    IFCHR:
-                       printf("%2d, %2d\t", major(inode.i_rdev), minor(inode.i_rdev));
-                       break;
-               default:
-                       printf("%6ld\t", inode.i_size);
-               }
-               printf("%3s %s\n", itype(inode.i_mode), name ? name : "");
+       return 1;
+}
+
+int
+nfs_filestat(vp, fsp)
+       struct vnode *vp;
+       struct filestat *fsp;
+{
+       struct nfsnode nfsnode;
+       register mode_t mode;
+
+       if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
+               dprintf(stderr, "can't read nfsnode at %x for pid %d\n",
+                       VTONFS(vp), Pid);
+               return 0;
+       }
+       fsp->fsid = nfsnode.n_vattr.va_fsid;
+       fsp->fileid = nfsnode.n_vattr.va_fileid;
+       fsp->size = nfsnode.n_size;
+       fsp->rdev = nfsnode.n_vattr.va_rdev;
+       mode = (mode_t)nfsnode.n_vattr.va_mode;
+       switch (vp->v_type) {
+       case VREG:
+               mode |= S_IFREG;
                break;
                break;
-       case DTYPE_SOCKET:
-               socktrans((struct socket *)g);
+       case VDIR:
+               mode |= S_IFDIR;
                break;
                break;
-#ifdef DTYPE_PORT
-       case DTYPE_PORT:
-               printf("* (fifo / named pipe)\n");
+       case VBLK:
+               mode |= S_IFBLK;
                break;
                break;
-#endif
-       default:
-               printf("* (unknown file type)\n");
-       }
+       case VCHR:
+               mode |= S_IFCHR;
+               break;
+       case VLNK:
+               mode |= S_IFLNK;
+               break;
+       case VSOCK:
+               mode |= S_IFSOCK;
+               break;
+       case VFIFO:
+               mode |= S_IFIFO;
+               break;
+       };
+       fsp->mode = mode;
+
+       return 1;
 }
 
 }
 
-static char *
-itype(mode)
-       u_short mode;
+
+char *
+getmnton(m)
+       struct mount *m;
 {
 {
-       switch(mode & IFMT) {
-       case IFCHR:
-               return("chr");
-       case IFDIR:
-               return("dir");
-       case IFBLK:
-               return("blk");
-       case IFREG:
-               return("reg");
-       case IFLNK:
-               return("lnk");
-       case IFSOCK:
-               return("soc");
-       default:
-               return("unk");
+       static struct mount mount;
+       static struct mtab {
+               struct mtab *next;
+               struct mount *m;
+               char mntonname[MNAMELEN];
+       } *mhead = NULL;
+       register struct mtab *mt;
+
+       for (mt = mhead; mt != NULL; mt = mt->next)
+               if (m == mt->m)
+                       return (mt->mntonname);
+       if (!KVM_READ(m, &mount, sizeof(struct mount))) {
+               fprintf(stderr, "can't read mount table at %x\n", m);
+               return (NULL);
        }
        }
-       /*NOTREACHED*/
+       if ((mt = malloc(sizeof (struct mtab))) == NULL) {
+               fprintf(stderr, "fstat: %s\n", strerror(errno));
+               exit(1);
+       }
+       mt->m = m;
+       bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
+       mt->next = mhead;
+       mhead = mt;
+       return (mt->mntonname);
 }
 
 }
 
-static
-socktrans(sock)
+void
+socktrans(sock, i)
        struct socket *sock;
        struct socket *sock;
+       int i;
 {
        static char *stypename[] = {
                "unused",       /* 0 */
 {
        static char *stypename[] = {
                "unused",       /* 0 */
@@ -374,51 +548,39 @@ socktrans(sock)
        int len;
        char dname[32], *strcpy();
 
        int len;
        char dname[32], *strcpy();
 
+       PREFIX(i);
+
        /* fill in socket */
        /* fill in socket */
-       (void)lseek(kmem, (off_t)sock, L_SET);
-       if (read(kmem, (char *)&so, sizeof(struct socket))
-           != sizeof(struct socket)) {
-               rerr2(errno, (int)sock, "socket");
-               return;
+       if (!KVM_READ(sock, &so, sizeof(struct socket))) {
+               dprintf(stderr, "can't read sock at %x\n", sock);
+               goto bad;
        }
 
        /* fill in protosw entry */
        }
 
        /* fill in protosw entry */
-       (void)lseek(kmem, (off_t)so.so_proto, L_SET);
-       if (read(kmem, (char *)&proto, sizeof(struct protosw))
-           != sizeof(struct protosw)) {
-               rerr2(errno, (int)so.so_proto, "protosw");
-               return;
+       if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
+               dprintf(stderr, "can't read protosw at %x", so.so_proto);
+               goto bad;
        }
 
        /* fill in domain */
        }
 
        /* fill in domain */
-       (void)lseek(kmem, (off_t)proto.pr_domain, L_SET);
-       if (read(kmem, (char *)&dom, sizeof(struct domain))
-           != sizeof(struct domain)) {
-               rerr2(errno, (int)proto.pr_domain, "domain");
-               return;
+       if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
+               dprintf(stderr, "can't read domain at %x\n", proto.pr_domain);
+               goto bad;
        }
 
        }
 
-       /*
-        * grab domain name
-        * kludge "internet" --> "inet" for brevity
-        */
-       if (dom.dom_family == AF_INET)
-               (void)strcpy(dname, "inet");
-       else {
-               (void)lseek(kmem, (off_t)dom.dom_name, L_SET);
-               if ((len = read(kmem, dname, sizeof(dname) - 1)) < 0) {
-                       rerr2(errno, (int)dom.dom_name, "char");
-                       dname[0] = '\0';
-               }
-               else
-                       dname[len] = '\0';
+       if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
+           sizeof(dname) - 1)) < 0) {
+               dprintf(stderr, "can't read domain name at %x\n",
+                       dom.dom_name);
+               dname[0] = '\0';
        }
        }
+       else
+               dname[len] = '\0';
 
        if ((u_short)so.so_type > STYPEMAX)
 
        if ((u_short)so.so_type > STYPEMAX)
-               printf("* (%s unk%d %x", dname, so.so_type, so.so_state);
+               printf("* %s ?%d", dname, so.so_type);
        else
        else
-               printf("* (%s %s %x", dname, stypename[so.so_type],
-                   so.so_state);
+               printf("* %s %s", dname, stypename[so.so_type]);
 
        /* 
         * protocol specific formatting
 
        /* 
         * protocol specific formatting
@@ -436,11 +598,13 @@ socktrans(sock)
                getinetproto(proto.pr_protocol);
                if (proto.pr_protocol == IPPROTO_TCP ) {
                        if (so.so_pcb) {
                getinetproto(proto.pr_protocol);
                if (proto.pr_protocol == IPPROTO_TCP ) {
                        if (so.so_pcb) {
-                               (void)lseek(kmem, (off_t)so.so_pcb, L_SET);
-                               if (read(kmem, (char *)&inpcb, sizeof(struct inpcb))
-                                   != sizeof(struct inpcb)){
-                                       rerr2(errno, (int)so.so_pcb, "inpcb");
-                                       return;
+                               if (kvm_read(kd, (u_long)so.so_pcb,
+                                   (char *)&inpcb, sizeof(struct inpcb))
+                                   != sizeof(struct inpcb)) {
+                                       dprintf(stderr, 
+                                           "can't read inpcb at %x\n",
+                                           so.so_pcb);
+                                       goto bad;
                                }
                                printf(" %x", (int)inpcb.inp_ppcb);
                        }
                                }
                                printf(" %x", (int)inpcb.inp_ppcb);
                        }
@@ -452,11 +616,11 @@ socktrans(sock)
                /* print address of pcb and connected pcb */
                if (so.so_pcb) {
                        printf(" %x", (int)so.so_pcb);
                /* print address of pcb and connected pcb */
                if (so.so_pcb) {
                        printf(" %x", (int)so.so_pcb);
-                       (void)lseek(kmem, (off_t)so.so_pcb, L_SET);
-                       if (read(kmem, (char *)&unpcb, sizeof(struct unpcb))
-                           != sizeof(struct unpcb)){
-                               rerr2(errno, (int)so.so_pcb, "unpcb");
-                               return;
+                       if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
+                           sizeof(struct unpcb)) != sizeof(struct unpcb)){
+                               dprintf(stderr, "can't read unpcb at %x\n",
+                                   so.so_pcb);
+                               goto bad;
                        }
                        if (unpcb.unp_conn) {
                                char shoconn[4], *cp;
                        }
                        if (unpcb.unp_conn) {
                                char shoconn[4], *cp;
@@ -468,7 +632,8 @@ socktrans(sock)
                                if (!(so.so_state & SS_CANTSENDMORE))
                                        *cp++ = '>';
                                *cp = '\0';
                                if (!(so.so_state & SS_CANTSENDMORE))
                                        *cp++ = '>';
                                *cp = '\0';
-                               printf(" %s %x", shoconn, (int)unpcb.unp_conn);
+                               printf(" %s %x", shoconn,
+                                   (int)unpcb.unp_conn);
                        }
                }
                break;
                        }
                }
                break;
@@ -476,14 +641,17 @@ socktrans(sock)
                /* print protocol number and socket address */
                printf(" %d %x", proto.pr_protocol, (int)sock);
        }
                /* print protocol number and socket address */
                printf(" %d %x", proto.pr_protocol, (int)sock);
        }
-       printf(")\n");
+       printf("\n");
+       return;
+bad:
+       printf("* error\n");
 }
 
 /*
  * getinetproto --
  *     print name of protocol number
  */
 }
 
 /*
  * getinetproto --
  *     print name of protocol number
  */
-static
+void
 getinetproto(number)
        int number;
 {
 getinetproto(number)
        int number;
 {
@@ -515,123 +683,33 @@ getinetproto(number)
        printf(" %s", cp);
 }
 
        printf(" %s", cp);
 }
 
-static
-readf()
-{
-       struct file lfile;
-       int i;
-
-       itrans(DTYPE_INODE, user.user.u_cdir, WD);
-       for (i = 0; i < NOFILE; i++) {
-               if (user.user.u_ofile[i] == 0)
-                       continue;
-               (void)lseek(kmem, (off_t)user.user.u_ofile[i], L_SET);
-               if (read(kmem, (char *)&lfile, sizeof(lfile))
-                   != sizeof(lfile)) {
-                       rerr1("file", N_KMEM);
-                       continue;
-               }
-               itrans(lfile.f_type, (struct inode *)lfile.f_data, i);
-       }
-}
-
-static
-devmatch(idev, inum, name)
-       dev_t idev;
-       ino_t inum;
-       char  **name;
-{
-       register DEVS *d;
-
-       for (d = devs; d; d = d->next)
-               if (d->dev == idev && (d->inum == 0 || d->inum == inum)) {
-                       *name = d->name;
-                       return(1);
-               }
-       return(0);
-}
-
-static
 getfname(filename)
        char *filename;
 {
        struct stat statbuf;
        DEVS *cur;
 getfname(filename)
        char *filename;
 {
        struct stat statbuf;
        DEVS *cur;
-       char *malloc();
 
        if (stat(filename, &statbuf)) {
 
        if (stat(filename, &statbuf)) {
-               perror(filename);
+               fprintf(stderr, "fstat: %s: %s\n", filename, strerror(errno));
                return(0);
        }
                return(0);
        }
-       if ((cur = (DEVS *)malloc(sizeof(DEVS))) == NULL) {
-               fprintf(stderr, "fstat: out of space.\n");
+       if ((cur = malloc(sizeof(DEVS))) == NULL) {
+               fprintf(stderr, "fstat: %s\n", strerror(errno));
                exit(1);
        }
        cur->next = devs;
        devs = cur;
 
                exit(1);
        }
        cur->next = devs;
        devs = cur;
 
-       /* if file is block special, look for open files on it */
-       if ((statbuf.st_mode & S_IFMT) != S_IFBLK) {
-               cur->inum = statbuf.st_ino;
-               cur->dev = statbuf.st_dev;
-       }
-       else {
-               cur->inum = 0;
-               cur->dev = statbuf.st_rdev;
-       }
+       cur->ino = statbuf.st_ino;
+       cur->fsid = statbuf.st_dev & 0xffff;
        cur->name = filename;
        return(1);
 }
 
        cur->name = filename;
        return(1);
 }
 
-static
-openfiles()
-{
-       if ((kmem = open(N_KMEM, O_RDONLY, 0)) < 0) {
-               perror(N_KMEM);
-               exit(1);
-       }
-       if ((mem = open(N_MEM, O_RDONLY, 0)) < 0) {
-               perror(N_MEM);
-               exit(1);
-       }
-       if ((swap = open(N_SWAP, O_RDONLY, 0)) < 0) {
-               perror(N_SWAP);
-               exit(1);
-       }
-}
-
-static
-rerr1(what, fromwhat)
-       char *what, *fromwhat;
-{
-       if (vflg)
-               printf("fstat: error reading %s from %s", what, fromwhat);
-}
-
-static
-rerr2(err, address, what)
-       int err, address;
-       char *what;
-{
-       if (vflg)
-               printf("error %d reading %s at %x from kmem\n", errno, what, address);
-}
-
-static long
-lgetw(loc)
-       off_t loc;
-{
-       long word;
-
-       (void)lseek(kmem, (off_t)loc, L_SET);
-       if (read(kmem, (char *)&word, sizeof(word)) != sizeof(word))
-               rerr2(errno, (int)loc, "word");
-       return(word);
-}
-
-static
+void
 usage()
 {
 usage()
 {
-       fputs("usage: fstat [-u user] [-p pid] [filename ...]\n", stderr);
+       (void)fprintf(stderr,
+ "usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");
        exit(1);
 }
        exit(1);
 }