home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / fstat / fstat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-17  |  16.3 KB  |  758 lines

  1. /*-
  2.  * Copyright (c) 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)fstat.c    5.32 (Berkeley) 6/17/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  *  fstat 
  46.  */
  47. #include <sys/param.h>
  48. #include <sys/time.h>
  49. #include <sys/proc.h>
  50. #include <sys/user.h>
  51. #ifdef SPPWAIT
  52. #define NEWVM
  53. #endif
  54. #ifndef NEWVM
  55. #include <machine/pte.h>
  56. #include <sys/vmmac.h>
  57. #endif
  58. #include <sys/stat.h>
  59. #include <sys/vnode.h>
  60. #include <sys/socket.h>
  61. #include <sys/socketvar.h>
  62. #include <sys/domain.h>
  63. #include <sys/protosw.h>
  64. #include <sys/unpcb.h>
  65. #include <sys/kinfo.h>
  66. #include <sys/filedesc.h>
  67. #define    KERNEL
  68. #define NFS
  69. #include <sys/file.h>
  70. #include <sys/mount.h>
  71. #include <ufs/quota.h>
  72. #include <ufs/inode.h>
  73. #include <nfs/nfsv2.h>
  74. #include <nfs/nfs.h>
  75. #include <nfs/nfsnode.h>
  76. #undef KERNEL
  77.  
  78. #include <net/route.h>
  79. #include <netinet/in.h>
  80. #include <netinet/in_systm.h>
  81. #include <netinet/ip.h>
  82. #include <netinet/in_pcb.h>
  83.  
  84. #include <errno.h>
  85. #include <nlist.h>
  86. #include <kvm.h>
  87. #include <pwd.h>
  88. #include <stdio.h>
  89. #include <paths.h>
  90. #include <ctype.h>
  91. #include <stdlib.h>
  92. #include <string.h>
  93.  
  94. #define    TEXT    -1
  95. #define    CDIR    -2
  96. #define    RDIR    -3
  97. #define    TRACE    -4
  98.  
  99. typedef struct devs {
  100.     struct    devs *next;
  101.     long    fsid;
  102.     ino_t    ino;
  103.     char    *name;
  104. } DEVS;
  105. DEVS *devs;
  106.  
  107. struct  filestat {
  108.     long    fsid;
  109.     long    fileid;
  110.     mode_t    mode;
  111.     u_long    size;
  112.     dev_t    rdev;
  113. };
  114.  
  115. #ifdef notdef
  116. struct nlist nl[] = {
  117.     { "" },
  118. };
  119. #endif
  120.  
  121. int     fsflg,    /* show files on same filesystem as file(s) argument */
  122.     pflg,    /* show files open by a particular pid */
  123.     uflg;    /* show files open by a particular (effective) user */
  124. int     checkfile; /* true if restricting to particular files or filesystems */
  125. int    nflg;    /* (numerical) display f.s. and rdev as dev_t */
  126. int    vflg;    /* display errors in locating kernel data objects etc... */
  127.  
  128. #define dprintf    if (vflg) fprintf
  129.  
  130. struct file **ofiles;    /* buffer of pointers to file structures */
  131. int maxfiles;
  132. #define ALLOC_OFILES(d)    \
  133.     if ((d) > maxfiles) { \
  134.         free(ofiles); \
  135.         ofiles = malloc((d) * sizeof(struct file *)); \
  136.         if (ofiles == NULL) { \
  137.             fprintf(stderr, "fstat: %s\n", strerror(errno)); \
  138.             exit(1); \
  139.         } \
  140.         maxfiles = (d); \
  141.     }
  142.  
  143. /*
  144.  * a kvm_read that returns true if everything is read 
  145.  */
  146. #define KVM_READ(kaddr, paddr, len) (kvm_read((kaddr), (paddr), (len)) == (len))
  147.  
  148. void dofiles(), getinetproto(), socktrans(), nfs_filestat(), ufs_filestat();
  149. void usage(), vtrans();
  150.  
  151. main(argc, argv)
  152.     int argc;
  153.     char **argv;
  154. {
  155.     extern char *optarg;
  156.     extern int optind;
  157.     register struct passwd *passwd;
  158.     struct proc *p;
  159.     int arg, ch, what;
  160.     char *namelist = NULL, *memfile = NULL;
  161.  
  162.     arg = 0;
  163.     what = KINFO_PROC_ALL;
  164.     while ((ch = getopt(argc, argv, "fnp:u:vNM")) != EOF)
  165.         switch((char)ch) {
  166.         case 'f':
  167.             fsflg = 1;
  168.             break;
  169.         case 'n':
  170.             nflg = 1;
  171.             break;
  172.         case 'p':
  173.             if (pflg++)
  174.                 usage();
  175.             if (!isdigit(*optarg)) {
  176.                 fprintf(stderr,
  177.                     "fstat: -p requires a process id\n");
  178.                 usage();
  179.             }
  180.             what = KINFO_PROC_PID;
  181.             arg = atoi(optarg);
  182.             break;
  183.         case 'u':
  184.             if (uflg++)
  185.                 usage();
  186.             if (!(passwd = getpwnam(optarg))) {
  187.                 fprintf(stderr, "%s: unknown uid\n",
  188.                     optarg);
  189.                 exit(1);
  190.             }
  191.             what = KINFO_PROC_UID;
  192.             arg = passwd->pw_uid;
  193.             break;
  194.         case 'v':
  195.             vflg = 1;
  196.             break;
  197.         case 'N':
  198.             namelist = optarg;
  199.             break;
  200.         case 'M':
  201.             memfile = optarg;
  202.             break;
  203.         case '?':
  204.         default:
  205.             usage();
  206.         }
  207.  
  208.     if (*(argv += optind)) {
  209.         for (; *argv; ++argv) {
  210.             if (getfname(*argv))
  211.                 checkfile = 1;
  212.         }
  213.         if (!checkfile)    /* file(s) specified, but none accessable */
  214.             exit(1);
  215.     }
  216.  
  217.     ALLOC_OFILES(256);    /* reserve space for file pointers */
  218.  
  219.     if (fsflg && !checkfile) {    
  220.         /* -f with no files means use wd */
  221.         if (getfname(".") == 0)
  222.             exit(1);
  223.         checkfile = 1;
  224.     }
  225.  
  226.     if (kvm_openfiles(namelist, memfile, NULL) == -1) {
  227.         fprintf(stderr, "fstat: %s\n", kvm_geterr());
  228.         exit(1);
  229.     }
  230. #ifdef notdef
  231.     if (kvm_nlist(nl) != 0) {
  232.         fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr());
  233.         exit(1);
  234.     }
  235. #endif
  236.     if (kvm_getprocs(what, arg) == -1) {
  237.         fprintf(stderr, "fstat: %s\n", kvm_geterr());
  238.         exit(1);
  239.     }
  240.     if (nflg)
  241.         printf("%s",
  242. "USER     CMD          PID   FD  DEV    INUM       MODE SZ|DV");
  243.     else
  244.         printf("%s",
  245. "USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV");
  246.     if (checkfile && fsflg == 0)
  247.         printf(" NAME\n");
  248.     else
  249.         putchar('\n');
  250.  
  251.     while ((p = kvm_nextproc()) != NULL) {
  252.         if (p->p_stat == SZOMB)
  253.             continue;
  254.         dofiles(p);
  255.     }
  256.     exit(0);
  257. }
  258.  
  259. char    *Uname, *Comm;
  260. int    Pid;
  261.  
  262. #define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
  263.     switch(i) { \
  264.     case TEXT: \
  265.         printf(" text"); \
  266.         break; \
  267.     case CDIR: \
  268.         printf("   wd"); \
  269.         break; \
  270.     case RDIR: \
  271.         printf(" root"); \
  272.         break; \
  273.     case TRACE: \
  274.         printf("   tr"); \
  275.         break; \
  276.     default: \
  277.         printf(" %4d", i); \
  278.         break; \
  279.     }
  280.  
  281. /*
  282.  * print open files attributed to this process
  283.  */
  284. void
  285. dofiles(p)
  286.     struct proc *p;
  287. {
  288.     int i, last;
  289.     struct file file;
  290. #ifdef NEWVM
  291.     struct filedesc0 filed0;
  292. #define    filed    filed0.fd_fd
  293.     struct eproc *ep;
  294. #else
  295.     struct filedesc filed;
  296. #endif
  297.  
  298.     extern char *user_from_uid();
  299. #ifndef NEWVM
  300.     struct vnode *xvptr;
  301. #endif
  302.  
  303. #ifdef NEWVM
  304.     ep = kvm_geteproc(p);
  305.     Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
  306. #else
  307.     Uname = user_from_uid(p->p_uid, 0);
  308. #endif
  309.     Pid = p->p_pid;
  310.     Comm = p->p_comm;
  311.  
  312.     if (p->p_fd == NULL)
  313.         return;
  314. #ifdef NEWVM
  315.     if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) {
  316.         dprintf(stderr, "can't read filedesc at %x for pid %d\n",
  317.             p->p_fd, Pid);
  318.         return;
  319.     }
  320. #else
  321.     if (!KVM_READ(p->p_fd, &filed, sizeof (filed))) {
  322.         dprintf(stderr, "can't read filedesc at %x for pid %d\n",
  323.             p->p_fd, Pid);
  324.         return;
  325.     }
  326. #endif
  327.     /*
  328.      * root directory vnode, if one
  329.      */
  330.     if (filed.fd_rdir)
  331.         vtrans(filed.fd_rdir, RDIR);
  332. #ifndef NEWVM
  333.     /*
  334.      * text vnode
  335.      */
  336.     if (p->p_textp && 
  337.         KVM_READ(&(p->p_textp->x_vptr), &xvptr, sizeof (struct vnode *)) &&
  338.         xvptr != NULL)
  339.         vtrans(xvptr, TEXT);
  340. #endif
  341.     /*
  342.      * current working directory vnode
  343.      */
  344.     vtrans(filed.fd_cdir, CDIR);
  345.     /*
  346.      * ktrace vnode, if one
  347.      */
  348.     if (p->p_tracep)
  349.         vtrans(p->p_tracep, TRACE);
  350.     /*
  351.      * open files
  352.      */
  353. #define FPSIZE    (sizeof (struct file *))
  354.     ALLOC_OFILES(filed.fd_lastfile);
  355. #ifdef NEWVM
  356.     if (filed.fd_nfiles > NDFILE) {
  357.         if (!KVM_READ(filed.fd_ofiles, ofiles,
  358.             filed.fd_lastfile * FPSIZE)) {
  359.             dprintf(stderr,
  360.                 "can't read file structures at %x for pid %d\n",
  361.                 filed.fd_ofiles, Pid);
  362.             return;
  363.         }
  364.     } else
  365.         bcopy(filed0.fd_dfiles, ofiles, filed.fd_lastfile * FPSIZE);
  366. #else
  367.     bcopy(filed.fd_ofile, ofiles, MIN(filed.fd_lastfile, NDFILE) * FPSIZE);
  368.     last = filed.fd_lastfile;
  369.     if ((last > NDFILE) && !KVM_READ(filed.fd_moreofiles, &ofiles[NDFILE],
  370.         (last - NDFILE) * FPSIZE)) {
  371.         dprintf(stderr, "can't read rest of files at %x for pid %d\n",
  372.             filed.fd_moreofiles, Pid);
  373.         return;
  374.     }
  375. #endif
  376.     for (i = 0; i <= filed.fd_lastfile; i++) {
  377.         if (ofiles[i] == NULL)
  378.             continue;
  379.         if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
  380.             dprintf(stderr, "can't read file %d at %x for pid %d\n",
  381.                 i, ofiles[i], Pid);
  382.             continue;
  383.         }
  384.         if (file.f_type == DTYPE_VNODE)
  385.             vtrans((struct vnode *)file.f_data, i);
  386.         else if (file.f_type == DTYPE_SOCKET && checkfile == 0)
  387.             socktrans((struct socket *)file.f_data, i);
  388.         else {
  389.             dprintf(stderr, 
  390.                 "unknown file type %d for file %d of pid %d\n",
  391.                 file.f_type, i, Pid);
  392.         }
  393.     }
  394. }
  395.  
  396. void
  397. vtrans(vp, i)
  398.     struct vnode *vp;
  399.     int i;
  400. {
  401.     extern char *devname();
  402.     struct vnode vn;
  403.     struct filestat fst;
  404.     char mode[15];
  405.     char *badtype, *filename, *getmnton();
  406.  
  407.     filename = badtype = NULL;
  408.     if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
  409.         dprintf(stderr, "can't read vnode at %x for pid %d\n",
  410.             vp, Pid);
  411.         return;
  412.     }
  413.     if (vn.v_type == VNON || vn.v_tag == VT_NON)
  414.         badtype = "none";
  415.     else if (vn.v_type == VBAD)
  416.         badtype = "bad";
  417.     else
  418.         switch (vn.v_tag) {
  419.         case VT_UFS:
  420.             ufs_filestat(&vn, &fst);
  421.             break;
  422.         case VT_MFS:
  423.             ufs_filestat(&vn, &fst);
  424.             break;
  425.         case VT_NFS:
  426.             nfs_filestat(&vn, &fst);
  427.             break;
  428.         default: {
  429.             static char unknown[10];
  430.             sprintf(badtype = unknown, "?(%x)", vn.v_tag);
  431.             break;;
  432.         }
  433.     }
  434.     if (checkfile) {
  435.         int fsmatch = 0;
  436.         register DEVS *d;
  437.  
  438.         if (badtype)
  439.             return;
  440.         for (d = devs; d != NULL; d = d->next)
  441.             if (d->fsid == fst.fsid) {
  442.                 fsmatch = 1;
  443.                 if (d->ino == fst.fileid) {
  444.                     filename = d->name;
  445.                     break;
  446.                 }
  447.             }
  448.         if (fsmatch == 0 || (filename == NULL && fsflg == 0))
  449.             return;
  450.     }
  451.     PREFIX(i);
  452.     if (badtype) {
  453.         (void)printf(" -         -  %10s    -\n", badtype);
  454.         return;
  455.     }
  456.     if (nflg)
  457.         (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
  458.     else
  459.         (void)printf(" %-8s", getmnton(vn.v_mount));
  460.     if (nflg)
  461.         (void)sprintf(mode, "%o", fst.mode);
  462.     else
  463.         strmode(fst.mode, mode);
  464.     (void)printf(" %6d %10s", fst.fileid, mode);
  465.     switch (vn.v_type) {
  466.     case VBLK:
  467.     case VCHR: {
  468.         char *name;
  469.  
  470.         if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? 
  471.             S_IFCHR : S_IFBLK)) == NULL))
  472.             printf("  %2d,%-2d", major(fst.rdev), minor(fst.rdev));
  473.         else
  474.             printf(" %6s", name);
  475.         break;
  476.     }
  477.     default:
  478.         printf(" %6d", fst.size);
  479.     }
  480.     if (filename && !fsflg)
  481.         printf(" %s", filename);
  482.         
  483.     putchar('\n');
  484. }
  485.  
  486. void
  487. ufs_filestat(vp, fsp)
  488.     struct vnode *vp;
  489.     struct filestat *fsp;
  490. {
  491.     struct inode *ip = VTOI(vp);
  492.  
  493.     fsp->fsid = ip->i_dev & 0xffff;
  494.     fsp->fileid = (long)ip->i_number;
  495.     fsp->mode = (mode_t)ip->i_mode;
  496.     fsp->size = (u_long)ip->i_size;
  497.     fsp->rdev = ip->i_rdev;
  498. }
  499.  
  500. void
  501. nfs_filestat(vp, fsp)
  502.     struct vnode *vp;
  503.     struct filestat *fsp;
  504. {
  505.     register struct nfsnode *np = VTONFS(vp);
  506.     register mode_t mode;
  507.  
  508.     fsp->fsid = np->n_vattr.va_fsid;
  509.     fsp->fileid = np->n_vattr.va_fileid;
  510.     fsp->size = np->n_size;
  511.     fsp->rdev = np->n_vattr.va_rdev;
  512.     mode = (mode_t)np->n_vattr.va_mode;
  513.     switch (vp->v_type) {
  514.     case VREG:
  515.         mode |= S_IFREG;
  516.         break;
  517.     case VDIR:
  518.         mode |= S_IFDIR;
  519.         break;
  520.     case VBLK:
  521.         mode |= S_IFBLK;
  522.         break;
  523.     case VCHR:
  524.         mode |= S_IFCHR;
  525.         break;
  526.     case VLNK:
  527.         mode |= S_IFLNK;
  528.         break;
  529.     case VSOCK:
  530.         mode |= S_IFSOCK;
  531.         break;
  532.     case VFIFO:
  533.         mode |= S_IFIFO;
  534.         break;
  535.     };
  536.     fsp->mode = mode;
  537. }
  538.  
  539.  
  540. char *
  541. getmnton(m)
  542.     struct mount *m;
  543. {
  544.     static struct mount mount;
  545.     static struct mtab {
  546.         struct mtab *next;
  547.         struct mount *m;
  548.         char mntonname[MNAMELEN];
  549.     } *mhead = NULL;
  550.     register struct mtab *mt;
  551.  
  552.     for (mt = mhead; mt != NULL; mt = mt->next)
  553.         if (m == mt->m)
  554.             return (mt->mntonname);
  555.     if (!KVM_READ(m, &mount, sizeof(struct mount))) {
  556.         fprintf(stderr, "can't read mount table at %x\n", m);
  557.         return (NULL);
  558.     }
  559.     if ((mt = malloc(sizeof (struct mtab))) == NULL) {
  560.         fprintf(stderr, "fstat: %s\n", strerror(errno));
  561.         exit(1);
  562.     }
  563.     mt->m = m;
  564.     bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
  565.     mt->next = mhead;
  566.     mhead = mt;
  567.     return (mt->mntonname);
  568. }
  569.  
  570. void
  571. socktrans(sock, i)
  572.     struct socket *sock;
  573.     int i;
  574. {
  575.     static char *stypename[] = {
  576.         "unused",    /* 0 */
  577.         "stream",     /* 1 */
  578.         "dgram",    /* 2 */
  579.         "raw",        /* 3 */
  580.         "rdm",        /* 4 */
  581.         "seqpak"    /* 5 */
  582.     };
  583. #define    STYPEMAX 5
  584.     struct socket    so;
  585.     struct protosw    proto;
  586.     struct domain    dom;
  587.     struct inpcb    inpcb;
  588.     struct unpcb    unpcb;
  589.     int len;
  590.     char dname[32], *strcpy();
  591.  
  592.     PREFIX(i);
  593.  
  594.     /* fill in socket */
  595.     if (!KVM_READ(sock, &so, sizeof(struct socket))) {
  596.         dprintf(stderr, "can't read sock at %x\n", sock);
  597.         goto bad;
  598.     }
  599.  
  600.     /* fill in protosw entry */
  601.     if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
  602.         dprintf(stderr, "can't read protosw at %x", so.so_proto);
  603.         goto bad;
  604.     }
  605.  
  606.     /* fill in domain */
  607.     if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
  608.         dprintf(stderr, "can't read domain at %x\n", proto.pr_domain);
  609.         goto bad;
  610.     }
  611.  
  612.     if ((len =
  613.         kvm_read(dom.dom_name, dname, sizeof(dname) - 1)) < 0) {
  614.         dprintf(stderr, "can't read domain name at %x\n",
  615.             dom.dom_name);
  616.         dname[0] = '\0';
  617.     }
  618.     else
  619.         dname[len] = '\0';
  620.  
  621.     if ((u_short)so.so_type > STYPEMAX)
  622.         printf("* %s ?%d", dname, so.so_type);
  623.     else
  624.         printf("* %s %s", dname, stypename[so.so_type]);
  625.  
  626.     /* 
  627.      * protocol specific formatting
  628.      *
  629.      * Try to find interesting things to print.  For tcp, the interesting
  630.      * thing is the address of the tcpcb, for udp and others, just the
  631.      * inpcb (socket pcb).  For unix domain, its the address of the socket
  632.      * pcb and the address of the connected pcb (if connected).  Otherwise
  633.      * just print the protocol number and address of the socket itself.
  634.      * The idea is not to duplicate netstat, but to make available enough
  635.      * information for further analysis.
  636.      */
  637.     switch(dom.dom_family) {
  638.     case AF_INET:
  639.         getinetproto(proto.pr_protocol);
  640.         if (proto.pr_protocol == IPPROTO_TCP ) {
  641.             if (so.so_pcb) {
  642.                 if (kvm_read(so.so_pcb, &inpcb,
  643.                     sizeof(struct inpcb))
  644.                     != sizeof(struct inpcb)) {
  645.                     dprintf(stderr, 
  646.                         "can't read inpcb at %x\n",
  647.                         so.so_pcb);
  648.                     goto bad;
  649.                 }
  650.                 printf(" %x", (int)inpcb.inp_ppcb);
  651.             }
  652.         }
  653.         else if (so.so_pcb)
  654.             printf(" %x", (int)so.so_pcb);
  655.         break;
  656.     case AF_UNIX:
  657.         /* print address of pcb and connected pcb */
  658.         if (so.so_pcb) {
  659.             printf(" %x", (int)so.so_pcb);
  660.             if (kvm_read(so.so_pcb, &unpcb,
  661.                 sizeof(struct unpcb)) != sizeof(struct unpcb)){
  662.                 dprintf(stderr, "can't read unpcb at %x\n",
  663.                     so.so_pcb);
  664.                 goto bad;
  665.             }
  666.             if (unpcb.unp_conn) {
  667.                 char shoconn[4], *cp;
  668.  
  669.                 cp = shoconn;
  670.                 if (!(so.so_state & SS_CANTRCVMORE))
  671.                     *cp++ = '<';
  672.                 *cp++ = '-';
  673.                 if (!(so.so_state & SS_CANTSENDMORE))
  674.                     *cp++ = '>';
  675.                 *cp = '\0';
  676.                 printf(" %s %x", shoconn,
  677.                     (int)unpcb.unp_conn);
  678.             }
  679.         }
  680.         break;
  681.     default:
  682.         /* print protocol number and socket address */
  683.         printf(" %d %x", proto.pr_protocol, (int)sock);
  684.     }
  685.     printf("\n");
  686.     return;
  687. bad:
  688.     printf("* error\n");
  689. }
  690.  
  691. /*
  692.  * getinetproto --
  693.  *    print name of protocol number
  694.  */
  695. void
  696. getinetproto(number)
  697.     int number;
  698. {
  699.     char *cp;
  700.  
  701.     switch(number) {
  702.     case IPPROTO_IP:
  703.         cp = "ip"; break;
  704.     case IPPROTO_ICMP:
  705.         cp ="icmp"; break;
  706.     case IPPROTO_GGP:
  707.         cp ="ggp"; break;
  708.     case IPPROTO_TCP:
  709.         cp ="tcp"; break;
  710.     case IPPROTO_EGP:
  711.         cp ="egp"; break;
  712.     case IPPROTO_PUP:
  713.         cp ="pup"; break;
  714.     case IPPROTO_UDP:
  715.         cp ="udp"; break;
  716.     case IPPROTO_IDP:
  717.         cp ="idp"; break;
  718.     case IPPROTO_RAW:
  719.         cp ="raw"; break;
  720.     default:
  721.         printf(" %d", number);
  722.         return;
  723.     }
  724.     printf(" %s", cp);
  725. }
  726.  
  727. getfname(filename)
  728.     char *filename;
  729. {
  730.     struct stat statbuf;
  731.     DEVS *cur;
  732.  
  733.     if (stat(filename, &statbuf)) {
  734.         fprintf(stderr, "fstat: %s: %s\n", strerror(errno),
  735.             filename);
  736.         return(0);
  737.     }
  738.     if ((cur = malloc(sizeof(DEVS))) == NULL) {
  739.         fprintf(stderr, "fstat: %s\n", strerror(errno));
  740.         exit(1);
  741.     }
  742.     cur->next = devs;
  743.     devs = cur;
  744.  
  745.     cur->ino = statbuf.st_ino;
  746.     cur->fsid = statbuf.st_dev & 0xffff;
  747.     cur->name = filename;
  748.     return(1);
  749. }
  750.  
  751. void
  752. usage()
  753. {
  754.     (void)fprintf(stderr,
  755.  "usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");
  756.     exit(1);
  757. }
  758.