diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
commit | f9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch) | |
tree | add7e996bac5289cdc55e6935750c352505560a9 /usr.bin/fstat | |
parent | be22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff) | |
download | FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz |
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/fstat')
-rw-r--r-- | usr.bin/fstat/Makefile | 10 | ||||
-rw-r--r-- | usr.bin/fstat/fstat.1 | 219 | ||||
-rw-r--r-- | usr.bin/fstat/fstat.c | 746 |
3 files changed, 975 insertions, 0 deletions
diff --git a/usr.bin/fstat/Makefile b/usr.bin/fstat/Makefile new file mode 100644 index 0000000..a8b50c2 --- /dev/null +++ b/usr.bin/fstat/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= fstat +CFLAGS+=-I/sys +DPADD= ${LIBKVM} +LDADD= -lkvm +BINGRP= kmem +BINMODE=2555 + +.include <bsd.prog.mk> diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1 new file mode 100644 index 0000000..1db0330 --- /dev/null +++ b/usr.bin/fstat/fstat.1 @@ -0,0 +1,219 @@ +.\" Copyright (c) 1987, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)fstat.1 8.3 (Berkeley) 2/25/94 +.\" +.Dd February 25, 1994 +.Dt FSTAT 1 +.Os BSD 4 +.Sh NAME +.Nm fstat +.Nd file status +.Sh SYNOPSIS +.Nm fstat +.Op Fl fnv +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl p Ar pid +.Op Fl u Ar user +.Op Ar filename... +.Sh DESCRIPTION +.Nm Fstat +identifies open files. +A file is considered open by a process if it was explicitly opened, +is the working directory, root directory, active pure text, or kernel +trace file for that process. +If no options are specified, +.Nm fstat +reports on all open files in the system. +.Pp +Options: +.Bl -tag -width Ds +.It Fl f +Restrict examination to files open in the same filesystems as +the named file arguments, or to the filesystem containing the +current directory if there are no additional filename arguments. +For example, to find all files open in the filesystem where the +directory +.Pa /usr/src +resides, type +.Dq Li fstat -f /usr/src . +.It Fl M +Extract values associated with the name list from the specified core +instead of the default +.Pa /dev/kmem . +.It Fl N +Extract the name list from the specified system instead of the default +.Pa /vmunix . +.It Fl n +Numerical format. Print the device number (maj,min) of the filesystem +the file resides in rather than the mount point name; for special +files, print the +device number that the special device refers to rather than the filename +in +.Pa /dev ; +and print the mode of the file in octal instead of symbolic form. +.It Fl p +Report all files open by the specified process. +.It Fl u +Report all files open by the specified user. +.It Fl v +Verbose mode. Print error messages upon failures to locate particular +system data structures rather than silently ignoring them. Most of +these data structures are dynamically created or deleted and it is +possible for them to disappear while +.Nm fstat +is running. This +is normal and unavoidable since the rest of the system is running while +.Nm fstat +itself is running. +.It Ar filename ... +Restrict reports to the specified files. +.El +.Pp +The following fields are printed: +.Bl -tag -width MOUNT +.It Li USER +The username of the owner of the process (effective uid). +.It Li CMD +The command name of the process. +.It Li PID +The process id. +.It Li FD +The file number in the per-process open file table or one of the following +special names: +.Pp +.Bd -ragged -offset indent -compact +text - pure text inode +wd - current working directory +root - root inode +tr - kernel trace file +.Ed +.Pp +If the file number is followed by an asterisk (``*''), the file is +not an inode, but rather a socket, +.Tn FIFO , +or there is an error. +In this case the remainder of the line doesn't +correspond to the remaining headers -- the format of the line +is described later under +.Sx Sockets . +.It Li MOUNT +If the +.Fl n +flag wasn't specified, this header is present and is the +pathname that the filesystem the file resides in is mounted on. +.It Li DEV +If the +.Fl n +flag is specified, this header is present and is the +major/minor number of the device that this file resides in. +.It Li INUM +The inode number of the file. +.It Li MODE +The mode of the file. If the +.Fl n +flag isn't specified, the mode is printed +using a symbolic format (see +.Xr strmode 3 ) ; +otherwise, the mode is printed +as an octal number. +.It Li SZ\&|DV +If the file is not a character or block special, prints the size of +the file in bytes. Otherwise, if the +.Fl n +flag is not specified, prints +the name of the special file as located in +.Pa /dev . +If that cannot be +located, or the +.Fl n +flag is specified, prints the major/minor device +number that the special device refers to. +.It Li R/W +This column describes the access mode that the file allows. +The letter ``r'' indicates open for reading; +the letter ``w'' indicates open for writing. +This field is useful when trying to find the processes that are +preventing a filesystem from being down graded to read-only. +.It Li NAME +If filename arguments are specified and the +.Fl f +flag is not, then +this field is present and is the name associated with the given file. +Normally the name cannot be determined since there is no mapping +from an open file back to the directory entry that was used to open +that file. Also, since different directory entries may reference +the same file (via +.Xr ln 2 ) , +the name printed may not be the actual +name that the process originally used to open that file. +.El +.Sh SOCKETS +The formating of open sockets depends on the protocol domain. +In all cases the first field is the domain name, the second field +is the socket type (stream, dgram, etc), and the third is the socket +flags field (in hex). +The remaining fields are protocol dependent. +For tcp, it is the address of the tcpcb, and for udp, the inpcb (socket pcb). +For unix domain sockets, its the address of the socket pcb and the address +of the connected pcb (if connected). +Otherwise the protocol number and address of the socket itself are printed. +The attempt is to make enough information available to +permit further analysis without duplicating +.Xr netstat 1 . +.Pp +For example, the addresses mentioned above are the addresses which the +.Dq Li netstat -A +command would print for tcp, udp, and unixdomain. +Note that since pipes are implemented using sockets, a pipe appears as a +connected unix domain stream socket. +A unidirectional unix domain socket indicates the direction of flow with +an arrow (``<-'' or ``->''), and a full duplex socket shows a double arrow +(``<->''). +.Sh BUGS +Since +.Nm fstat +takes a snapshot of the system, it is only correct for a very short period +of time. +.Sh SEE ALSO +.Xr netstat 1 , +.Xr nfsstat 1 , +.Xr ps 1 , +.Xr systat 1 , +.Xr vmstat 1 , +.Xr iostat 8 , +.Xr pstat 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 tahoe . diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c new file mode 100644 index 0000000..90d7304 --- /dev/null +++ b/usr.bin/fstat/fstat.c @@ -0,0 +1,746 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)fstat.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/stat.h> +#include <sys/vnode.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/unpcb.h> +#include <sys/sysctl.h> +#include <sys/filedesc.h> +#define KERNEL +#include <sys/file.h> +#include <ufs/ufs/quota.h> +#include <ufs/ufs/inode.h> +#undef KERNEL +#define NFS +#include <sys/mount.h> +#include <nfs/nfsv2.h> +#include <nfs/rpcv2.h> +#include <nfs/nfs.h> +#include <nfs/nfsnode.h> +#undef NFS + +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> + +#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[] = { + { "" }, +}; +#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); \ + } + +/* + * 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)) + +kvm_t *kd; + +int ufs_filestat(), nfs_filestat(); +void dofiles(), getinetproto(), socktrans(); +void usage(), vtrans(); + +main(argc, argv) + int argc; + char **argv; +{ + 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(); + if (!isdigit(*optarg)) { + fprintf(stderr, + "fstat: -p requires a process id\n"); + usage(); + } + what = KERN_PROC_PID; + arg = atoi(optarg); + break; + case 'u': + if (uflg++) + usage(); + if (!(passwd = getpwnam(optarg))) { + fprintf(stderr, "%s: unknown uid\n", + optarg); + exit(1); + } + what = KERN_PROC_UID; + arg = passwd->pw_uid; + break; + case 'v': + vflg = 1; + break; + case '?': + default: + usage(); + } + + if (*(argv += optind)) { + for (; *argv; ++argv) { + if (getfname(*argv)) + checkfile = 1; + } + if (!checkfile) /* file(s) specified, but none accessable */ + exit(1); + } + + ALLOC_OFILES(256); /* reserve space for file pointers */ + + if (fsflg && !checkfile) { + /* -f with no files means use wd */ + if (getfname(".") == 0) + exit(1); + checkfile = 1; + } + + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + if ((kd = kvm_open(nlistf, memf, NULL, O_RDONLY, NULL)) == NULL) { + fprintf(stderr, "fstat: %s\n", kvm_geterr(kd)); + exit(1); + } +#ifdef notdef + if (kvm_nlist(kd, nl) != 0) { + fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr(kd)); + exit(1); + } +#endif + if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) { + fprintf(stderr, "fstat: %s\n", kvm_geterr(kd)); + exit(1); + } + if (nflg) + printf("%s", +"USER CMD PID FD DEV INUM MODE SZ|DV R/W"); + else + printf("%s", +"USER CMD PID FD MOUNT INUM MODE SZ|DV R/W"); + if (checkfile && fsflg == 0) + printf(" NAME\n"); + else + putchar('\n'); + + for (plast = &p[cnt]; p < plast; ++p) { + if (p->kp_proc.p_stat == SZOMB) + continue; + dofiles(p); + } + exit(0); +} + +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; \ + } + +/* + * print open files attributed to this process + */ +void +dofiles(kp) + struct kinfo_proc *kp; +{ + int i, last; + struct file file; + struct filedesc0 filed0; +#define filed filed0.fd_fd + struct proc *p = &kp->kp_proc; + struct eproc *ep = &kp->kp_eproc; + + extern char *user_from_uid(); + + Uname = user_from_uid(ep->e_ucred.cr_uid, 0); + Pid = p->p_pid; + Comm = p->p_comm; + + if (p->p_fd == NULL) + return; + if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) { + dprintf(stderr, "can't read filedesc at %x for pid %d\n", + p->p_fd, Pid); + return; + } + /* + * root directory vnode, if one + */ + if (filed.fd_rdir) + vtrans(filed.fd_rdir, RDIR, FREAD); + /* + * current working directory vnode + */ + vtrans(filed.fd_cdir, CDIR, FREAD); + /* + * ktrace vnode, if one + */ + if (p->p_tracep) + vtrans(p->p_tracep, TRACE, FREAD|FWRITE); + /* + * 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, file.f_flag); + 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); + } + } +} + +void +vtrans(vp, i, flag) + struct vnode *vp; + int i; + int flag; +{ + struct vnode vn; + struct filestat fst; + char rw[3], 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;; + } + } + 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; + } + PREFIX(i); + if (badtype) { + (void)printf(" - - %10s -\n", badtype); + return; + } + if (nflg) + (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid)); + else + (void)printf(" %-8s", getmnton(vn.v_mount)); + if (nflg) + (void)sprintf(mode, "%o", fst.mode); + else + strmode(fst.mode, mode); + (void)printf(" %6d %10s", fst.fileid, mode); + switch (vn.v_type) { + case VBLK: + case VCHR: { + char *name; + + if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? + S_IFCHR : S_IFBLK)) == NULL)) + printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev)); + else + printf(" %6s", name); + break; + } + default: + printf(" %6d", fst.size); + } + rw[0] = '\0'; + if (flag & FREAD) + strcat(rw, "r"); + if (flag & FWRITE) + strcat(rw, "w"); + printf(" %2s", rw); + if (filename && !fsflg) + printf(" %s", filename); + putchar('\n'); +} + +int +ufs_filestat(vp, fsp) + struct vnode *vp; + struct filestat *fsp; +{ + struct inode inode; + + if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) { + dprintf(stderr, "can't read inode at %x for pid %d\n", + VTOI(vp), Pid); + return 0; + } + fsp->fsid = inode.i_dev & 0xffff; + fsp->fileid = (long)inode.i_number; + fsp->mode = (mode_t)inode.i_mode; + fsp->size = (u_long)inode.i_size; + fsp->rdev = inode.i_rdev; + + return 1; +} + +int +nfs_filestat(vp, fsp) + struct vnode *vp; + struct filestat *fsp; +{ + struct nfsnode nfsnode; + register mode_t mode; + + if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) { + dprintf(stderr, "can't read nfsnode at %x for pid %d\n", + VTONFS(vp), Pid); + return 0; + } + fsp->fsid = nfsnode.n_vattr.va_fsid; + fsp->fileid = nfsnode.n_vattr.va_fileid; + fsp->size = nfsnode.n_size; + fsp->rdev = nfsnode.n_vattr.va_rdev; + mode = (mode_t)nfsnode.n_vattr.va_mode; + switch (vp->v_type) { + case VREG: + mode |= S_IFREG; + break; + 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; +} + + +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); + } + 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); +} + +void +socktrans(sock, i) + struct socket *sock; + int i; +{ + 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 */ + if (!KVM_READ(sock, &so, sizeof(struct socket))) { + dprintf(stderr, "can't read sock at %x\n", sock); + goto bad; + } + + /* fill in protosw entry */ + 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 */ + if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) { + dprintf(stderr, "can't read domain at %x\n", proto.pr_domain); + goto bad; + } + + if ((len = kvm_read(kd, (u_long)dom.dom_name, dname, + sizeof(dname) - 1)) < 0) { + dprintf(stderr, "can't read domain name at %x\n", + dom.dom_name); + dname[0] = '\0'; + } + else + dname[len] = '\0'; + + if ((u_short)so.so_type > STYPEMAX) + printf("* %s ?%d", dname, so.so_type); + else + printf("* %s %s", dname, stypename[so.so_type]); + + /* + * 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. + */ + switch(dom.dom_family) { + case AF_INET: + getinetproto(proto.pr_protocol); + if (proto.pr_protocol == IPPROTO_TCP ) { + if (so.so_pcb) { + if (kvm_read(kd, (u_long)so.so_pcb, + (char *)&inpcb, sizeof(struct inpcb)) + != sizeof(struct inpcb)) { + dprintf(stderr, + "can't read inpcb at %x\n", + so.so_pcb); + goto bad; + } + printf(" %x", (int)inpcb.inp_ppcb); + } + } + 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) { + 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); + } + } + break; + default: + /* print protocol number and socket address */ + printf(" %d %x", proto.pr_protocol, (int)sock); + } + printf("\n"); + return; +bad: + printf("* error\n"); +} + +/* + * getinetproto -- + * print name of protocol number + */ +void +getinetproto(number) + int number; +{ + char *cp; + + 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; + } + printf(" %s", cp); +} + +getfname(filename) + char *filename; +{ + struct stat statbuf; + DEVS *cur; + + if (stat(filename, &statbuf)) { + fprintf(stderr, "fstat: %s: %s\n", filename, strerror(errno)); + return(0); + } + if ((cur = malloc(sizeof(DEVS))) == NULL) { + fprintf(stderr, "fstat: %s\n", strerror(errno)); + exit(1); + } + cur->next = devs; + devs = cur; + + cur->ino = statbuf.st_ino; + cur->fsid = statbuf.st_dev & 0xffff; + cur->name = filename; + return(1); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n"); + exit(1); +} |