BSD 4_3_Reno release
[unix-history] / usr / src / usr.bin / fstat / fstat.c
index 7e4de37..fa0e48c 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.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #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.3 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)fstat.c    5.25 (Berkeley) 6/29/90";
+#endif /* not lint */
 
 /*
  *  fstat 
  */
 
 /*
  *  fstat 
  */
-#include <stdio.h>
-#include <ctype.h>
-#include <nlist.h>
-#include <pwd.h>
+#include <machine/pte.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/proc.h>
 #include <sys/user.h>
 #include <sys/proc.h>
-#include <machine/pte.h> 
-#include <sys/vm.h>
 #include <sys/text.h>
 #include <sys/stat.h>
 #include <sys/text.h>
 #include <sys/stat.h>
-#include <math.h>
-#include <sys/vlimit.h>
-#include <sys/inode.h>
+#include <sys/time.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/vmmac.h>
+#define        KERNEL
+#define NFS
 #include <sys/file.h>
 #include <sys/file.h>
+#include <sys/mount.h>
+#include <ufs/quota.h>
+#include <ufs/inode.h>
+#include <nfs/nfsv2.h>
+#include <nfs/nfs.h>
+#include <nfs/nfsnode.h>
 #undef KERNEL
 
 #undef KERNEL
 
-#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, vflg, nproc, pflg;
-int sflg, kflg; /*4.2*/
-int argaddr; /*4.2*/
-
-struct devs {
-       struct devs *next;
-       dev_t dev;
-       int inum;
-} devs;
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
 
 
-#define clear(x)       ((int)x & 0x7fffffff)
+#include <kvm.h>
+#include <paths.h>
+#include <ctype.h>
+#include <nlist.h>
+#include <pwd.h>
+#include <string.h>
+#include <stdio.h>
 
 
-struct pte *Sysmap = 0;
+#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
 
 
-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
+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... */
 
 
-char   *kmemf, *memf, *swapf, *nlistf;
+#define dprintf        if (vflg) fprintf
 
 
-extern int     errno;
-char   stdoutBuf[BUFSIZ];
+extern int errno;
+off_t lseek();
 
 main(argc, argv)
 
 main(argc, argv)
-char **argv;
+       int argc;
+       char **argv;
 {
 {
-       register int i, j;
-       off_t procp;
-       dev_t   dev;
-
-       argv++;
-       while (*argv) {
-               if (strcmp(*argv, "-v") == 0) {
-                       vflg++;
-                       argv++;
-                       continue;
-               } 
-               if (strcmp(*argv, "-u") == 0) {
-                       if (uflg++)
+       register struct passwd *passwd;
+       int what = KINFO_PROC_ALL, arg = 0;
+       struct passwd *getpwnam(), *getpwuid();
+       struct proc *p;
+       extern char *optarg;
+       extern int optind;
+       int ch;
+       char *malloc();
+
+
+       while ((ch = getopt(argc, argv, "p:u:fnv")) != EOF)
+               switch((char)ch) {
+               case 'p':
+                       if (pflg++)
+                               usage();
+                       if (!isdigit(*optarg)) {
+                               fputs("fstat: -p option requires a process id.\n", stderr);
                                usage();
                                usage();
-                       if ((uid = getuname(*(++argv))) < 0) {
-                               fprintf(stderr, "%s: unknown user\n", *argv);
-                               exit(1);
                        }
                        }
-                       argv++;
-                       continue;
-               } 
-               if (strcmp(*argv, "-f") == 0) {
-                       fflg++;
-                       if (getfname(*(++argv)) < 0) {
-                               perror(*argv);
+                       what = KINFO_PROC_PID;
+                       arg = atoi(optarg);
+                       break;
+               case 'u':
+                       if (uflg++)
+                               usage();
+                       if (!(passwd = getpwnam(optarg))) {
+                               fprintf(stderr, "%s: unknown uid\n",
+                                   optarg);
                                exit(1);
                        }
                                exit(1);
                        }
-                       argv++;
-                       continue;
+                       what = KINFO_PROC_UID;
+                       arg = passwd->pw_uid;
+                       break;
+               case 'f':
+                       fsflg++;
+                       break;
+               case 'n':
+                       nflg++;
+                       break;
+               case 'v':
+                       vflg++;
+                       break;
+               case '?':
+               default:
+                       usage();
                }
 
                }
 
-               if (strcmp(*argv, "-p") == 0) {
-                       if (pflg++ || ((pid = Atoi(*(++argv))) <= 0)) {
-                               usage();
-                               perror(*argv);
-                               exit(1);
-                       }
-                       argv++;
-                       continue;
+       if (*(argv += optind)) {
+               for (; *argv; ++argv) {
+                       if (getfname(*argv))
+                               checkfile = 1;
                }
                }
-               /* otherwise its a file argument */
-               fflg++;
-               if (getfname(*argv) < 0) {
-                       perror(*argv);
+               if (!checkfile) /* file(s) specified, but none accessable */
                        exit(1);
                        exit(1);
-               }
-               argv++;
-               continue;
-       }
-
-       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 (fsflg && !checkfile) {      
+               /* -f with no files means use wd */
+               if (getfname(".") == 0)
+                       exit(1);
+               checkfile = 1;
        }
        }
-       exit(0);
-}
 
 
-long
-getw(loc)
-       off_t loc;
-{
-       long word;
-
-       lseek(kmem, (long) loc, 0);
-       if (read(kmem, (char *) &word, sizeof (word)) != sizeof (word))
-               vprintf("error reading kmem at %x\n", loc);
-       return (word);
-}
-
-openfiles()
-{
-
-       kmemf = "kmem";
-       kmem = open(kmemf, 0);
-       if (kmem < 0) {
-               perror(kmemf);
+       /* modify the following to make work on dead kernels */
+       if (kvm_openfiles(NULL, NULL, NULL) == -1) {
+               fprintf(stderr, "fstat: %s\n", kvm_geterr());
                exit(1);
        }
                exit(1);
        }
-       memf = "mem";
-       mem = open(memf, 0);
-       if (mem < 0) {
-               perror(memf);
+#ifdef notdef
+       if (kvm_nlist(nl) != 0) {
+               fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr());
                exit(1);
        }
                exit(1);
        }
-       swapf = "drum";
-       swap = open(swapf, 0);
-       if (swap < 0) {
-               perror(swapf);
+#endif
+       if (kvm_getprocs(what, arg) == -1) {
+               fprintf(stderr, "fstat: %s\n", kvm_geterr());
                exit(1);
        }
                exit(1);
        }
-}
+       if (nflg)
+fputs("USER     CMD        PID   FD  DEV    INUM       MODE SZ|DV", stdout);
+       else
+fputs("USER     CMD        PID   FD MOUNT      INUM MODE         SZ|DV", stdout);
+       if (checkfile && fsflg == 0)
+               fputs(" NAME\n", stdout);       
+       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);
+       while ((p = kvm_nextproc()) != NULL) {
+               if (p->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 %-8.8s %5d", Uname, Comm, Pid); \
+       switch(i) { \
+       case TEXT: \
+               fputs(" text", stdout); \
+               break; \
+       case CDIR: \
+               fputs("   wd", stdout); \
+               break; \
+       case RDIR: \
+               fputs(" root", stdout); \
+               break; \
+       case TRACE: \
+               fputs("   tr", stdout); \
+               break; \
+       default: \
+               printf(" %4d", i); \
+               break; \
+       }
 
 
-doproc()
+/*
+ * print open files attributed to this process
+ */
+dofiles(p)
+       struct proc *p;
 {
 {
-       struct passwd   *getpwuid();
-
-
-       if (uflg && mproc->p_uid != uid)
-               return;
-       if (pflg && mproc->p_pid != pid)
-               return;
-       if (mproc->p_stat != SZOMB && getu() == 0)
+       int i;
+       struct file file;
+       struct user *up = kvm_getu(p);
+       struct vnode *xvptr;
+       extern char *user_from_uid();
+
+       Uname = user_from_uid(p->p_uid, 0);
+       Pid = p->p_pid;
+       Comm = p->p_comm;
+
+       if (up == NULL) {
+               dprintf(stderr, "can't read u for pid %d\n", Pid);
                return;
                return;
-       uname = getpwuid(mproc->p_uid)->pw_name;
-       dotext();
-       getf();
+       }
+       /*
+        * root directory vnode, if one
+        */
+       if (up->u_rdir)
+               vtrans(up->u_rdir, RDIR);
+       /*
+        * text vnode
+        */
+       if (p->p_textp && 
+           kvm_read(&(p->p_textp->x_vptr), &xvptr,
+           sizeof (struct vnode *)) == sizeof (struct vnode *) &&
+           xvptr != NULL)
+               vtrans(xvptr, TEXT);
+       /*
+        * current working directory vnode
+        */
+       vtrans(up->u_cdir, CDIR);
+       /*
+        * ktrace vnode, if one
+        */
+       if (p->p_tracep)
+               vtrans(p->p_tracep, TRACE);
+       /*
+        * open files
+        */
+       for (i = 0; i <= up->u_lastfile; i++) {
+               if (up->u_ofile[i] == 0)
+                       continue;
+               if (kvm_read(up->u_ofile[i], &file, sizeof (struct file)) !=
+                   sizeof (struct file)) {
+                       dprintf(stderr, "can't read file %d for pid %d\n",
+                               i, Pid);
+                       continue;
+               }
+               if (file.f_type == DTYPE_VNODE)
+                       vtrans((struct vnode *)file.f_data, i);
+               else if (file.f_type == DTYPE_SOCKET && 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()
+vtrans(vp, i)
+       struct vnode *vp;
 {
 {
-       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);
+       struct vnode vn;
+       struct filestat fst;
+       char *filename = NULL;
+       char *badtype = NULL;
+       char *getmnton();
+       extern char *devname();
+       char mode[15];
+
+       if (kvm_read((off_t)vp, &vn, sizeof (struct vnode)) != 
+           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:
+                       ufs_filestat(&vn, &fst);
+                       break;
+               case VT_MFS:
+                       ufs_filestat(&vn, &fst);
+                       break;
+               case VT_NFS:
+                       nfs_filestat(&vn, &fst);
+                       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()
+ufs_filestat(vp, fsp)
+       struct vnode *vp;
+       struct filestat *fsp;
 {
 {
-       struct text     text;
+       struct inode *ip = VTOI(vp);
 
 
-       lseek(kmem, (long) mproc->p_textp, 0);
-       if (read(kmem, (char *) &text, sizeof(text)) != sizeof(text)) {
-               cantread("text table", kmemf);
-               return;
-       }
-       if (text.x_flag == 0)
-               return;
-       itrans(DTYPE_INODE, text.x_iptr, TEXT);
+       fsp->fsid = ip->i_dev & 0xffff;
+       fsp->fileid = (long)ip->i_number;
+       fsp->mode = (mode_t)ip->i_mode;
+       fsp->size = (u_long)ip->i_size;
+       fsp->rdev = ip->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)
+nfs_filestat(vp, fsp)
+       struct vnode *vp;
+       struct filestat *fsp;
 {
 {
-       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);
-       }
+       register struct nfsnode *np = VTONFS(vp);
+       register mode_t mode;
+
+       fsp->fsid = np->n_vattr.va_fsid;
+       fsp->fileid = np->n_vattr.va_fileid;
+       fsp->size = np->n_size;
+       fsp->rdev = np->n_vattr.va_rdev;
+       mode = (mode_t)np->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;
 }
 
 }
 
-itrans(ftype, g, fno)
-struct inode   *g;  /* if ftype is inode */
-{
-       struct inode    inode;
-       dev_t   idev;
-       int     type;
-       char    *comm;
-
-       if (g == 0 && ! fflg) {
-               goto skip;
-       }
-       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;
-       }
-       idev = inode.i_dev;
-       if (fflg && !devmatch(idev, inode.i_number))
-               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);
-
-       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");
-       }
-#endif DTYPE_PORT
-       else {
-               printf("* (unknown file type)\n");
-       }
-}
-devmatch(idev, inum)
-dev_t idev;
-int inum;
+char *
+getmnton(m)
+       struct mount *m;
 {
 {
-       struct devs *d = &devs;
-       for (d = d->next; d; d = d->next) {
-               if (d->dev == idev) {
-                       if (d->inum == 0)
-                               return(1);
-                       if (d->inum == inum)
-                               return(1);
-               }
+       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((off_t)m, &mount, sizeof(struct mount)) != 
+           sizeof(struct mount)) {
+               fprintf(stderr, "can't read mount table at %x\n", m);
+               return (NULL);
        }
        }
-       return(0);
+       if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) {
+               fprintf(stderr, "out of memory\n");
+               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;
+socktrans(sock, i)
+       struct socket *sock;
 {
 {
-       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((off_t)sock, (char *)&so, sizeof(struct socket))
+           != 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((off_t)so.so_proto, (char *)&proto, sizeof(struct protosw))
+           != 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((off_t)proto.pr_domain, (char *)&dom, sizeof(struct domain))
+           != 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;
+       /*
+        * grab domain name
+        * kludge "internet" --> "inet" for brevity
+        */
+       if (dom.dom_family == AF_INET)
+               strcpy(dname, "inet");
+       else {
+               if ((len = kvm_read((off_t)dom.dom_name, dname, sizeof(dname) - 1)) < 0) {
+                       dprintf(stderr, "can't read domain name at %x\n",
+                               dom.dom_name);
+                       dname[0] = '\0';
                }
                }
-               if (c == '\0')
-                       break;
-               *cp = c;
+               else
+                       dname[len] = '\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);
+       if ((u_short)so.so_type > STYPEMAX)
+               printf("* %s ?%d", dname, so.so_type);
        else
        else
-               stype = stypename[so.so_type];
-
-       /* print sock type, sock state, and domain name */
-       printf("* (%s %s %x", dname, stype, so.so_state);
+               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)) 
+                               if (kvm_read((off_t)so.so_pcb, (char *)&inpcb, sizeof(struct inpcb))
                                    != sizeof(struct inpcb)){
                                    != sizeof(struct inpcb)){
-                                       vprintf("error %d reading inpcb at %x from kmem\n",
-                                            errno, so.so_pcb);
-                                       return;
+                                       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)) 
+                       printf(" %x", (int)so.so_pcb);
+                       if (kvm_read((off_t)so.so_pcb, (char *)&unpcb, sizeof(struct unpcb))
                            != sizeof(struct unpcb)){
                            != sizeof(struct unpcb)){
-                               vprintf("error %d reading unpcb at %x from kmem\n",
-                                    errno, so.so_pcb);
-                               return;
+                               dprintf(stderr, "can't read unpcb at %x\n",
+                                       so.so_pcb);
+                               goto bad;
                        }
                        if (unpcb.unp_conn) {
                        }
                        if (unpcb.unp_conn) {
-                               char shoconn[4]; *shoconn = 0;
+                               char shoconn[4], *cp;
+
+                               cp = shoconn;
                                if (!(so.so_state & SS_CANTRCVMORE))
                                if (!(so.so_state & SS_CANTRCVMORE))
-                                       strcat(shoconn, "<");
-                               strcat(shoconn,"-");
+                                       *cp++ = '<';
+                               *cp++ = '-';
                                if (!(so.so_state & SS_CANTSENDMORE))
                                if (!(so.so_state & SS_CANTSENDMORE))
-                                       strcat(shoconn, ">");
-                               printf(" %s %x", shoconn, unpcb.unp_conn);
+                                       *cp++ = '>';
+                               *cp = '\0';
+                               printf(" %s %x", shoconn,
+                                   (int)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
+ */
 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;
-       struct devs *d, *oldd;
-       dev_t dev;
-       int inum;
+       struct stat statbuf;
+       DEVS *cur;
+       char *malloc();
 
 
-       if (stat(filename, &statbuf) != 0)
-               return(-1);
-
-       /*
-        *      if file is block special, look for open files on it
-        */
-       if ((statbuf.st_mode & S_IFMT) != S_IFBLK) {
-               inum = statbuf.st_ino;
-               dev = statbuf.st_dev;
-       } else {
-               inum = 0;
-               dev = statbuf.st_rdev;
+       if (stat(filename, &statbuf)) {
+               fprintf(stderr, "fstat: %s: %s\n", strerror(errno),
+                   filename);
+               return(0);
        }
        }
-       for (d = oldd = &devs; d; oldd = d, d = d->next)
-               ;
-       d = (struct devs *)emalloc(sizeof(struct devs));
-       oldd->next = d;
-       d->next = 0;
-       d->dev = dev;
-       d->inum = inum;
-}
-
-Atoi(p)
-register char *p;
-{
-       register int n = 0;
+       if ((cur = (DEVS *)malloc(sizeof(DEVS))) == NULL) {
+               fprintf(stderr, "fstat: out of space.\n");
+               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;
+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 [-u user] [-p pid] [filename ...]\n");
+       exit(1);
 }
 }