kinfo_proc.h gone, stuff moved to <sys/sysctl.h>
[unix-history] / usr / src / usr.bin / fstat / fstat.c
index a923e33..6b4678a 100644 (file)
-/*
- * Copyright (c) 1987 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+/*-
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %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";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)fstat.c    5.1 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)fstat.c    5.44 (Berkeley) %G%";
+#endif /* not lint */
 
 
-/*
- *  fstat 
- */
-#include <stdio.h>
-#include <ctype.h>
-#include <nlist.h>
-#include <pwd.h>
 #include <sys/param.h>
 #include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/tty.h>
-#include <sys/dir.h>
-#include <sys/user.h>
+#include <sys/time.h>
 #include <sys/proc.h>
 #include <sys/proc.h>
-#include <machine/pte.h> 
-#include <sys/vm.h>
-#include <sys/text.h>
+#include <sys/user.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <math.h>
-#include <sys/vlimit.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/socket.h>
 #include <sys/socketvar.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
-#include <net/route.h>
-#include <netinet/in.h>
-#include <netinet/in_pcb.h>
 #include <sys/unpcb.h>
 #include <sys/unpcb.h>
-#define KERNEL
+#include <sys/sysctl.h>
+#include <sys/filedesc.h>
+#define        KERNEL
 #include <sys/file.h>
 #include <sys/file.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
 #undef KERNEL
 #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
 
 
-#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 ULTRIX
-
-char *emalloc();
-char *getinetproto();
-
-#define vprintf        if (vflg) printf
-#define WD     -1
-#define TEXT   -2
-
-int    pcbpf, nswap, kmem, mem, swap, uid, pid;
-int    uflg, fflg, inum, Mdev, mdev, special, vflg, nproc, pflg;
-int sflg, kflg; /*4.2*/
-int argaddr; /*4.2*/
-
-#define clear(x)       ((int)x & 0x7fffffff)
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
 
 
-struct pte *Sysmap = 0;
+#include <ctype.h>
+#include <errno.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define        TEXT    -1
+#define        CDIR    -2
+#define        RDIR    -3
+#define        TRACE   -4
+
+typedef struct devs {
+       struct  devs *next;
+       long    fsid;
+       ino_t   ino;
+       char    *name;
+} DEVS;
+DEVS *devs;
+
+struct  filestat {
+       long    fsid;
+       long    fileid;
+       mode_t  mode;
+       u_long  size;
+       dev_t   rdev;
+};
 
 
+#ifdef notdef
 struct nlist nl[] = {
 struct nlist nl[] = {
-       { "_proc" },
-#define        X_PROC          0
-       { "_Usrptmap" },
-#define        X_USRPTMA       1
-       { "_usrpt" },
-#define        X_USRPT         2
-       { "_nswap" },
-#define        X_NSWAP         3
-       { "_nproc" },
-#define        X_NPROC         4
-       { "_Sysmap" },
-#define SSYSMAP                5
-       { "_Syssize" },
-#define SSYSSIZE       6
        { "" },
 };
        { "" },
 };
+#endif
+
+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); \
+       }
 
 
-char   *stypename[] = {
-       "unused",       /* 0 */
-       "stream",       /* 1 */
-       "dgram",        /* 2 */
-       "raw",          /* 3 */
-       "rdm",          /* 4 */
-       "seqpak"        /* 5 */
-};
-#define STYPEMAX 5
-
-char   *uname;
-
-
-struct proc proc[8], *mproc;           /* 8 = a few, for less syscalls */
-struct pte *Usrptma, *usrpt;
-
-int    paduser1;               /* avoid hardware mem clobbering botch */
-union {
-       struct  user user;
-       char    upages[UPAGES][NBPG];
-} user;
-int    paduser2;               /* avoid hardware mem clobbering botch */
-#define u      user.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))
 
 
-char   *kmemf, *memf, *swapf, *nlistf;
+kvm_t *kd;
 
 
-extern int     errno;
-char   stdoutBuf[BUFSIZ];
+int ufs_filestat(), nfs_filestat();
+void dofiles(), getinetproto(), socktrans();
+void usage(), vtrans();
 
 main(argc, argv)
 
 main(argc, argv)
-char **argv;
+       int argc;
+       char **argv;
 {
 {
-       register int i, j;
-       off_t procp;
-       dev_t   dev;
-
-       argv++;
-       while (--argc > 0) {
-               if (strcmp(*argv, "-v") == 0) {
-                       vflg++;
-                       argv++;
-                       continue;
-               } 
-               if (strcmp(*argv, "-u") == 0) {
-                       if (uflg++)
+       extern char *optarg;
+       extern int optind;
+       register struct passwd *passwd;
+       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) {
+               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();
                                usage();
-                       if ((uid = getuname(*(++argv))) < 0) {
-                               fprintf(stderr, "%s: unknown user\n", *argv);
-                               exit(1);
-                       }
-                       --argc;
-                       argv++;
-                       continue;
-               } 
-               if (strcmp(*argv, "-f") == 0) {
-                       if (fflg++)
+                       if (!isdigit(*optarg)) {
+                               fprintf(stderr,
+                                   "fstat: -p requires a process id\n");
                                usage();
                                usage();
-                       if ((dev = getfname(*(++argv))) < 0) {
-                               perror(*argv);
-                               exit(1);
                        }
                        }
-                       --argc;
-                       argv++;
-                       continue;
-               }
-
-               if (strcmp(*argv, "-p") == 0) {
-                       if (pflg++ || ((pid = Atoi(*(++argv))) <= 0)) {
+                       what = KERN_PROC_PID;
+                       arg = atoi(optarg);
+                       break;
+               case 'u':
+                       if (uflg++)
                                usage();
                                usage();
-                               perror(*argv);
+                       if (!(passwd = getpwnam(optarg))) {
+                               fprintf(stderr, "%s: unknown uid\n",
+                                   optarg);
                                exit(1);
                        }
                                exit(1);
                        }
-                       --argc;
-                       argv++;
-                       continue;
-               }
-
-               /* admit missing -u, -f, -p */
-               /* it's an expert system! */
-               if ((pid = Atoi(*argv)) > 0) {
-                       if (pflg++)
-                               usage();
-                       continue;
-               }
-               if (fflg && uflg)
+                       what = KERN_PROC_UID;
+                       arg = passwd->pw_uid;
+                       break;
+               case 'v':
+                       vflg = 1;
+                       break;
+               case '?':
+               default:
                        usage();
                        usage();
-               if (uflg) {
-                       /* it must be a file */
-                       fflg++;
-                       if ((dev = getfname(*argv)) < 0) {
-                               perror(*argv);
-                               exit(1);
-                       }
-                       argv++;
-                       continue;
                }
                }
-               if (fflg) {
-                       /* it must be a user */
-                       uflg++;
-                       if ((uid = getuname(*argv)) < 0) {
-                               fprintf(stderr,
-                                       "%s: unknown user\n", *argv);
-                               exit(1);
-                       }
-                       argv++;
-                       continue;
-               }
-               /* !uflg && !fflg -- which is it? */
-               if ((dev = getfname(*argv)) >= 0)
-                       fflg++;         /* could be a file */
-               if ((uid = getuname(*argv)) >= 0)
-                       uflg++;         /* could be a user */
-               if ((!uflg ^ !fflg) == 0)
-                       usage();        /* could be either/neither */
-               argv++;
-               continue;
-       }
 
 
-       if (fflg) {
-               Mdev = major(dev);
-               mdev = minor(dev);
-       }
-
-       if (chdir("/dev") < 0) {
-               perror("/dev");
-               exit(1);
-       }
-
-       printf("user\t cmd\t      pid    fd\tdevice\tinode\t  size\ttype\n");
-       openfiles();
-       getkvars();
-       procp = getw((off_t) nl[X_PROC].n_value);
-       nproc = getw((off_t) nl[X_NPROC].n_value);
-       for (i=0; i<nproc; i += 8) {
-               lseek(kmem, (long) procp, 0);
-               j = nproc - i;
-               if (j > 8)
-                       j = 8;
-               j *= sizeof (struct proc);
-               if (read(kmem, (char *) proc, j) != j)
-                       cantread("proc table", kmemf);
-               procp += j;
-               for (j = j / sizeof (struct proc) - 1; j >= 0; j--) {
-                       mproc = &proc[j];
-                       if (mproc->p_stat == 0)
-                               continue;
-                       doproc();
+       if (*(argv += optind)) {
+               for (; *argv; ++argv) {
+                       if (getfname(*argv))
+                               checkfile = 1;
                }
                }
+               if (!checkfile) /* file(s) specified, but none accessable */
+                       exit(1);
        }
        }
-       exit(0);
-}
 
 
-long
-getw(loc)
-       off_t loc;
-{
-       long word;
+       ALLOC_OFILES(256);      /* reserve space for file pointers */
 
 
-       lseek(kmem, (long) loc, 0);
-       if (read(kmem, (char *) &word, sizeof (word)) != sizeof (word))
-               vprintf("error reading kmem at %x\n", loc);
-       return (word);
-}
+       if (fsflg && !checkfile) {      
+               /* -f with no files means use wd */
+               if (getfname(".") == 0)
+                       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());
 
 
-       kmemf = "kmem";
-       kmem = open(kmemf, 0);
-       if (kmem < 0) {
-               perror(kmemf);
+       if ((kd = kvm_open(nlistf, memf, NULL, O_RDONLY, NULL)) == NULL) {
+               fprintf(stderr, "fstat: %s\n", kvm_geterr(kd));
                exit(1);
        }
                exit(1);
        }
-       memf = "mem";
-       mem = open(memf, 0);
-       if (mem < 0) {
-               perror(memf);
+#ifdef notdef
+       if (kvm_nlist(kd, nl) != 0) {
+               fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr(kd));
                exit(1);
        }
                exit(1);
        }
-       swapf = "drum";
-       swap = open(swapf, 0);
-       if (swap < 0) {
-               perror(swapf);
+#endif
+       if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) {
+               fprintf(stderr, "fstat: %s\n", kvm_geterr(kd));
                exit(1);
        }
                exit(1);
        }
-}
+       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');
 
 
-getkvars()
-{
-       nlistf = "/vmunix";
-       nlist(nlistf, nl);
-       if (nl[0].n_type == 0) {
-               fprintf(stderr, "%s: No namelist\n", nlistf);
-               exit(1);
-       }
-       Usrptma = (struct pte *) nl[X_USRPTMA].n_value;
-       usrpt = (struct pte *) nl[X_USRPT].n_value;
-       lseek(kmem, (long) nl[X_NSWAP].n_value, 0);
-       if (read(kmem, (char *) &nswap, sizeof (nswap)) != sizeof (nswap)) {
-               cantread("nswap", kmemf);
-               exit(1);
+       for (plast = &p[cnt]; p < plast; ++p) {
+               if (p->kp_proc.p_stat == SZOMB)
+                       continue;
+               dofiles(p);
        }
        }
+       exit(0);
 }
 
 }
 
-cantread(what, fromwhat)
-       char *what, *fromwhat;
-{
-
-       vprintf("fstat: error reading %s from %s", what, fromwhat);
-}
+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; \
+       }
 
 
-doproc()
+/*
+ * print open files attributed to this process
+ */
+void
+dofiles(kp)
+       struct kinfo_proc *kp;
 {
 {
-       struct passwd   *getpwuid();
+       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();
 
 
-       if (uflg && mproc->p_uid != uid)
-               return;
-       if (pflg && mproc->p_pid != pid)
+       Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
+       Pid = p->p_pid;
+       Comm = p->p_comm;
+
+       if (p->p_fd == NULL)
                return;
                return;
-       if (mproc->p_stat != SZOMB && getu() == 0)
+       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;
                return;
-       uname = getpwuid(mproc->p_uid)->pw_name;
-       dotext();
-       getf();
+       }
+       /*
+        * 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);
+               }
+       }
 }
 
 }
 
-getu()
+void
+vtrans(vp, i)
+       struct vnode *vp;
+       int i;
 {
 {
-       struct pte *pteaddr, apte;
-       struct pte arguutl[UPAGES+CLSIZE];
-       register int i;
-       int ncl, size;
-
-       size = sizeof (struct user);
-       if ((mproc->p_flag & SLOAD) == 0) {
-               if (swap < 0)
-                       return (0);
-               (void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
-               if (read(swap, (char *)&user.user, size) != size) {
-                       fprintf(stderr, "ps: cant read u for pid %d from %s\n",
-                           mproc->p_pid, swapf);
-                       return (0);
+       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;
+       }
+       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;;
                }
                }
-               pcbpf = 0;
-               argaddr = 0;
-               return (1);
        }
        }
-       pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
-       klseek(kmem, (long)pteaddr, 0);
-       if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
-               printf("fstat: cant read indir pte to get u for pid %d from %s\n",
-                   mproc->p_pid, swapf);
-               return (0);
+       if (checkfile) {
+               int fsmatch = 0;
+               register DEVS *d;
+
+               if (badtype)
+                       return;
+               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;
        }
        }
-       klseek(mem,
-           (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
-               0);
-       if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
-               printf("fstat: cant read page table for u of pid %d from %s\n",
-                   mproc->p_pid, kmemf);
-               return (0);
+       PREFIX(i);
+       if (badtype) {
+               (void)printf(" -         -  %10s    -\n", badtype);
+               return;
        }
        }
-       if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
-               argaddr = ctob(arguutl[0].pg_pfnum);
+       if (nflg)
+               (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
        else
        else
-               argaddr = 0;
-       pcbpf = arguutl[CLSIZE].pg_pfnum;
-       ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
-       while (--ncl >= 0) {
-               i = ncl * CLSIZE;
-               klseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
-               if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
-                       printf("fstat: cant read page %d of u of pid %d from %s\n",
-                           arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
-                       return(0);
-               }
+               (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;
        }
        }
-       return (1);
+       default:
+               printf(" %6d", fst.size);
+       }
+       if (filename && !fsflg)
+               printf(" %s", filename);
+               
+       putchar('\n');
 }
 
 }
 
-#define        NMAX    8
-#define        NUID    2048
-
-dotext()
+int
+ufs_filestat(vp, fsp)
+       struct vnode *vp;
+       struct filestat *fsp;
 {
 {
-       struct text     text;
+       struct inode inode;
 
 
-       lseek(kmem, (long) mproc->p_textp, 0);
-       if (read(kmem, (char *) &text, sizeof(text)) != sizeof(text)) {
-               cantread("text table", kmemf);
-               return;
+       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;
        }
        }
-       if (text.x_flag == 0)
-               return;
-       itrans(DTYPE_INODE, text.x_iptr, TEXT);
-}
+       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;
 
 
-char   *itypename[] = {
-       "unk",
-#define UNK 0  /* unknown */
-       "chr",
-#define CHR 1  
-       "dir",
-#define DIR 2
-       "blk",
-#define BLK 3
-       "reg",
-#define REG 4
-       "lnk",
-#define LNK 5
-       "soc"
-#define SOC 6
-};
-
-itype(mode)
-{
-       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(0);
-       }
+       return 1;
 }
 
 }
 
-itrans(ftype, g, fno)
-struct inode   *g;  /* if ftype is inode */
+int
+nfs_filestat(vp, fsp)
+       struct vnode *vp;
+       struct filestat *fsp;
 {
 {
-       struct inode    inode;
-       dev_t   idev;
-       int     type;
-       char    *comm;
+       struct nfsnode nfsnode;
+       register mode_t mode;
 
 
-       if (g == 0 && ! fflg) {
-               goto skip;
+       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;
        }
        }
-       lseek(kmem, (long) g, 0);
-       if (read(kmem, (char *) &inode, sizeof(inode))
-                                       != sizeof(inode)) {
-               vprintf("error %d reading inode at %x from kmem\n", errno, g);
-               return;
-       }
-       if (special)
-               idev = inode.i_dev;
-       else
-               idev = inode.i_dev;
-       if (fflg && major(idev) != Mdev)
-               return; 
-       if (fflg && minor(idev) != mdev)
-               return; 
-       if (inum && inode.i_number != inum)
-               return;
-skip:
-       if (mproc->p_pid == 0)
-               comm = "swapper";
-       else if (mproc->p_pid == 2)
-               comm = "pagedaemon";
-       else
-               comm = u.u_comm;
-       printf("%-8.8s %-10.10s %5d  ", uname, comm, mproc->p_pid);
-       if (fno == WD)
-               printf("  wd");
-       else if (fno == TEXT)
-               printf("text");
-       else
-               printf("%4d", fno);
+       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;
+       case VDIR:
+               mode |= S_IFDIR;
+               break;
+       case VBLK:
+               mode |= S_IFBLK;
+               break;
+       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;
+}
 
 
-       if (g == 0) {
-               printf("* (deallocated)\n");
-               return;
-       }
 
 
-       if (ftype == DTYPE_INODE) {
-               type = itype(inode.i_mode);  /* determine inode type */
-               printf("\t%2d, %2d\t%5d\t%6d\t%3s\n", major(inode.i_dev), minor(inode.i_dev),
-                       inode.i_number, type == SOC?0:inode.i_size, itypename[type]);
-       }
-       else if (ftype == DTYPE_SOCKET) {
-               socktrans((struct socket *)g);
-       }
-#ifdef DTYPE_PORT
-       else if (ftype == DTYPE_PORT) {
-               printf("* (fifo / named pipe)\n");
+char *
+getmnton(m)
+       struct mount *m;
+{
+       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);
        }
        }
-#endif DTYPE_PORT
-       else {
-               printf("* (unknown file type)\n");
+       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);
 }
 
 }
 
-socktrans(sock)
-struct socket *sock;
+void
+socktrans(sock, i)
+       struct socket *sock;
+       int i;
 {
 {
-       struct socket   so;
-       struct protosw  proto;
-       struct domain   dom;
-       char    dname[32];      /* domain name, e.g. "inet" */
-       char    c;
-       char    *cp;
-       int     i;
-       char    *stype;
-       struct inpcb    inpcb;
-       struct unpcb    unpcb;
+       static char *stypename[] = {
+               "unused",       /* 0 */
+               "stream",       /* 1 */
+               "dgram",        /* 2 */
+               "raw",          /* 3 */
+               "rdm",          /* 4 */
+               "seqpak"        /* 5 */
+       };
+#define        STYPEMAX 5
+       struct socket   so;
+       struct protosw  proto;
+       struct domain   dom;
+       struct inpcb    inpcb;
+       struct unpcb    unpcb;
+       int len;
+       char dname[32], *strcpy();
+
+       PREFIX(i);
 
        /* fill in socket */
 
        /* fill in socket */
-       lseek(kmem, (long) sock, 0);
-       if (read(kmem, (char *) &so, sizeof(struct socket)) 
-           != sizeof(struct socket)){
-               vprintf("error %d reading socket at %x from kmem\n", errno, sock);
-               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 */
-       lseek(kmem, (long) so.so_proto, 0);
-       if (read(kmem, (char *) &proto, sizeof(struct protosw)) 
-           != sizeof(struct protosw)){
-               vprintf("error %d reading protosw at %x from kmem\n", errno, so.so_proto);
-               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 */
-       lseek(kmem, (long) proto.pr_domain, 0);
-       if (read(kmem, (char *) &dom, sizeof(struct domain)) 
-           != sizeof(struct domain)){
-               vprintf("error %d reading domain at %x from kmem\n", errno, proto.pr_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 */
-       lseek(kmem, (long) dom.dom_name, 0);
-       for (cp=dname, i=0; i < 30; i++, cp++) { /* 30 leaves room for null byte */
-               if (read(kmem, (char *)&c, sizeof(char)) != sizeof(char)) {
-                   vprintf("error %d reading char at %x from kmem\n", errno, dom.dom_name+i);
-                   break;
-               }
-               if (c == '\0')
-                       break;
-               *cp = c;
+       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';
        }
        }
-       *cp='\0';
-       /* kludge "internet" --> "inet" for brevity */
-       if (dom.dom_family == AF_INET)  
-               strcpy(dname, "inet");
-
-       if (so.so_type < 1 || so.so_type > STYPEMAX)
-               stype = (char *)sprintf(emalloc(10),"unk%d", so.so_type);
        else
        else
-               stype = stypename[so.so_type];
+               dname[len] = '\0';
 
 
-       /* print sock type, sock state, and domain name */
-       printf("* (%s %s %x", dname, stype, so.so_state);
+       if ((u_short)so.so_type > STYPEMAX)
+               printf("* %s ?%d", dname, so.so_type);
+       else
+               printf("* %s %s", dname, stypename[so.so_type]);
 
        /* 
 
        /* 
-        * protocol specific formating 
+        * protocol specific formatting
         *
         *
-        * Try to find interesting things to print.  For tcp, the
-        * interesting thing is the address of the tcpcb, for udp
-        * and others, just the inpcb (socket pcb).  For unix
-        * domain, its the address of the socket pcb and the address of
-        * the connected pcb (if connected).  Otherwise just print
-        * the protocol number and address of the socket itself. The
-        * idea is not to duplicate netstat, but to make available
-        * enough information for further analysis. 
+        * Try to find interesting things to print.  For tcp, the interesting
+        * thing is the address of the tcpcb, for udp and others, just the
+        * inpcb (socket pcb).  For unix domain, its the address of the socket
+        * pcb and the address of the connected pcb (if connected).  Otherwise
+        * just print the protocol number and address of the socket itself.
+        * The idea is not to duplicate netstat, but to make available enough
+        * information for further analysis.
         */
         */
-       if (dom.dom_family == AF_INET) {
-               /* print name of protocol number */
-               printf(" %s", getinetproto(proto.pr_protocol));
+       switch(dom.dom_family) {
+       case AF_INET:
+               getinetproto(proto.pr_protocol);
                if (proto.pr_protocol == IPPROTO_TCP ) {
                        if (so.so_pcb) {
                if (proto.pr_protocol == IPPROTO_TCP ) {
                        if (so.so_pcb) {
-                               lseek(kmem, (long) so.so_pcb, 0);
-                               if (read(kmem, (char *) &inpcb, sizeof(struct inpcb)) 
-                                   != sizeof(struct inpcb)){
-                                       vprintf("error %d reading inpcb at %x from kmem\n",
-                                            errno, so.so_pcb);
-                                       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", inpcb.inp_ppcb);
+                               printf(" %x", (int)inpcb.inp_ppcb);
                        }
                        }
-               } else if (so.so_pcb) {
-                               printf(" %x", so.so_pcb);
                }
                }
-       } else if (dom.dom_family == AF_UNIX) { 
+               else if (so.so_pcb)
+                       printf(" %x", (int)so.so_pcb);
+               break;
+       case AF_UNIX:
                /* print address of pcb and connected pcb */
                if (so.so_pcb) {
                /* print address of pcb and connected pcb */
                if (so.so_pcb) {
-                       printf(" %x", so.so_pcb);
-                       lseek(kmem, (long) so.so_pcb, 0);
-                       if (read(kmem, (char *) &unpcb, sizeof(struct unpcb)) 
-                           != sizeof(struct unpcb)){
-                               vprintf("error %d reading unpcb at %x from kmem\n",
-                                    errno, so.so_pcb);
-                               return;
+                       printf(" %x", (int)so.so_pcb);
+                       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;
+
+                               cp = shoconn;
+                               if (!(so.so_state & SS_CANTRCVMORE))
+                                       *cp++ = '<';
+                               *cp++ = '-';
+                               if (!(so.so_state & SS_CANTSENDMORE))
+                                       *cp++ = '>';
+                               *cp = '\0';
+                               printf(" %s %x", shoconn,
+                                   (int)unpcb.unp_conn);
                        }
                        }
-                       if (unpcb.unp_conn)
-                               printf(" -> %x", unpcb.unp_conn);
                }
                }
-       } else {
+               break;
+       default:
                /* print protocol number and socket address */
                /* print protocol number and socket address */
-               printf(" %d %x", proto.pr_protocol, sock);
+               printf(" %d %x", proto.pr_protocol, (int)sock);
        }
        }
-       printf(")\n");
+       printf("\n");
+       return;
+bad:
+       printf("* error\n");
 }
 
 }
 
-char *
+/*
+ * getinetproto --
+ *     print name of protocol number
+ */
+void
 getinetproto(number)
 getinetproto(number)
-{
-       switch(number) {
-       case 0:  return("ip");
-       case 1:  return("icmp");
-       case 2:  return("ggp");
-       case 6:  return("tcp");
-       case 8:  return("egp");
-       case 12: return("pup");
-       case 17: return("udp");
-       case 22: return("idp");
-       case 255: return("raw");
-       default: return((char *)sprintf(emalloc(16),"%d",number));
-       }
-}
-               
-char *
-emalloc(size)
+       int number;
 {
        char *cp;
 {
        char *cp;
-       cp = (char *)malloc(size);
-       if (cp < 0) {
-               fprintf(stderr,"Out of space.\n");
-               exit(1);
-       }
-       return(cp);
-}
-
-struct  file  *
-getf()
-{
-       int     i;
-       struct file     file;
 
 
-       itrans(DTYPE_INODE, u.u_cdir, WD);
-       for (i = 0; i < NOFILE; i++) {
-               if (u.u_ofile[i] == 0)
-                       continue;
-               lseek(kmem, (long) u.u_ofile[i], 0);
-               if (read(kmem, (char *) &file, sizeof(file)) != sizeof(file)) {
-                       cantread("file", kmemf);
-                       continue;
-               }
-               /*printf("flag: %x count: %x ",file.f_flag, file.f_count);
-               /*fflush(stdout);
-                */
-               itrans(file.f_type, file.f_data, i); 
+       switch(number) {
+       case IPPROTO_IP:
+               cp = "ip"; break;
+       case IPPROTO_ICMP:
+               cp ="icmp"; break;
+       case IPPROTO_GGP:
+               cp ="ggp"; break;
+       case IPPROTO_TCP:
+               cp ="tcp"; break;
+       case IPPROTO_EGP:
+               cp ="egp"; break;
+       case IPPROTO_PUP:
+               cp ="pup"; break;
+       case IPPROTO_UDP:
+               cp ="udp"; break;
+       case IPPROTO_IDP:
+               cp ="idp"; break;
+       case IPPROTO_RAW:
+               cp ="raw"; break;
+       default:
+               printf(" %d", number);
+               return;
        }
        }
-}
-
-usage()
-{
-       fputs("usage: fstat [-u user] [-f filename] [-p pid]\n", stderr);
-       exit(1);
-}
-
-getuname(uname)
-char   *uname;
-{
-       struct passwd   *passwd, *getpwnam();
-       
-       if ((passwd = getpwnam(uname)) == NULL)
-               return(-1);
-       return(passwd->pw_uid);
+       printf(" %s", cp);
 }
 
 getfname(filename)
 }
 
 getfname(filename)
-char   *filename;
+       char *filename;
 {
 {
-       struct  stat statbuf;
-
-       if (stat(filename, &statbuf) != 0)
-               return(-1);
+       struct stat statbuf;
+       DEVS *cur;
 
 
-       /*
-        *      if file is block special, look for open files on it
-        */
-       if ((statbuf.st_mode & S_IFMT) != S_IFBLK) {
-               inum = statbuf.st_ino;
-               return(statbuf.st_dev);
-       } else {
-               special++;
-               inum = 0;
-               return(statbuf.st_rdev);
+       if (stat(filename, &statbuf)) {
+               fprintf(stderr, "fstat: %s: %s\n", filename, strerror(errno));
+               return(0);
        }
        }
-}
-
-Atoi(p)
-register char *p;
-{
-       register int n = 0;
+       if ((cur = malloc(sizeof(DEVS))) == NULL) {
+               fprintf(stderr, "fstat: %s\n", strerror(errno));
+               exit(1);
+       }
+       cur->next = devs;
+       devs = cur;
 
 
-       while(*p >= '0' && *p <= '9')
-               n = n*10 + *p++ - '0';
-       return(*p ? -n : n);
+       cur->ino = statbuf.st_ino;
+       cur->fsid = statbuf.st_dev & 0xffff;
+       cur->name = filename;
+       return(1);
 }
 
 }
 
-klseek(fd, loc, off)
-       int fd;
-       long loc;
-       int off;
+void
+usage()
 {
 {
-       static int      sizeSysmap;
-
-       if( kflg && Sysmap == 0)
-               {/* initialize Sysmap */
-
-               sizeSysmap = nl[SSYSSIZE].n_value * sizeof( struct pte);
-               Sysmap = (struct pte *)calloc( sizeSysmap, 1);
-               lseek( kmem, clear( nl[SSYSMAP].n_value), 0);
-               if( read( kmem, Sysmap, sizeSysmap) != sizeSysmap)
-                       {
-                       printf( "Cant read system page table\n");
-                       exit(1);
-                       }
-               }
-       if( kflg && (loc&0x80000000))
-               {/* do mapping for kernel virtual addresses */
-               struct pte *ptep;
-
-               loc &= 0x7fffffff;
-               ptep = &Sysmap[btop(loc)];
-               if( (char *)ptep - (char *)Sysmap > sizeSysmap)
-                       {
-                       printf( "no system pte for %s\n", loc);
-                       exit(1);
-                       }
-               if( ptep->pg_v == 0)
-                       {
-                       printf( "system pte invalid for %x\n", loc);
-                       exit(1);
-                       }
-               loc = (off_t)((loc&PGOFSET) + ptob(ptep->pg_pfnum));
-               }
-       (void) lseek(fd, (long)loc, off);
+       (void)fprintf(stderr,
+ "usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");
+       exit(1);
 }
 }