* Copyright (c) 1988 The Regents of the University of California.
* %sccs.include.redist.c%
"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)fstat.c 5.33 (Berkeley) %G%";
#include <sys/socketvar.h>
#include <sys/filedesc.h>
#include <netinet/in_systm.h>
#include <netinet/in_pcb.h>
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 */
#define ALLOC_OFILES(d) \
ofiles = malloc((d) * sizeof(struct file *)); \
fprintf(stderr, "fstat: %s\n", strerror(errno)); \
* a kvm_read that returns true if everything is read
#define KVM_READ(kaddr, paddr, len) (kvm_read((kaddr), (paddr), (len)) == (len))
void dofiles(), getinetproto(), socktrans(), nfs_filestat(), ufs_filestat();
register struct passwd
*passwd
;
char *namelist
= NULL
, *memfile
= NULL
;
while ((ch
= getopt(argc
, argv
, "fnp:u:vNM")) != EOF
)
"fstat: -p requires a process id\n");
if (!(passwd
= getpwnam(optarg
))) {
fprintf(stderr
, "%s: unknown uid\n",
if (!checkfile
) /* file(s) specified, but none accessable */
ALLOC_OFILES(256); /* reserve space for file pointers */
if (fsflg
&& !checkfile
) {
/* -f with no files means use wd */
if (kvm_openfiles(namelist
, memfile
, NULL
) == -1) {
fprintf(stderr
, "fstat: %s\n", kvm_geterr());
if (kvm_nlist(nl
) != 0) {
fprintf(stderr
, "fstat: no namelist: %s\n", kvm_geterr());
if (kvm_getprocs(what
, arg
) == -1) {
fprintf(stderr
, "fstat: %s\n", kvm_geterr());
"USER CMD PID FD DEV INUM MODE SZ|DV");
"USER CMD PID FD MOUNT INUM MODE SZ|DV");
if (checkfile
&& fsflg
== 0)
while ((p
= kvm_nextproc()) != NULL
) {
#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
* print open files attributed to this process
#define filed filed0.fd_fd
extern char *user_from_uid();
Uname
= user_from_uid(ep
->e_ucred
.cr_uid
, 0);
Uname
= user_from_uid(p
->p_uid
, 0);
if (!KVM_READ(p
->p_fd
, &filed0
, sizeof (filed0
))) {
dprintf(stderr
, "can't read filedesc at %x for pid %d\n",
if (!KVM_READ(p
->p_fd
, &filed
, sizeof (filed
))) {
dprintf(stderr
, "can't read filedesc at %x for pid %d\n",
* root directory vnode, if one
vtrans(filed
.fd_rdir
, RDIR
);
KVM_READ(&(p
->p_textp
->x_vptr
), &xvptr
, sizeof (struct vnode
*)) &&
* current working directory vnode
vtrans(filed
.fd_cdir
, CDIR
);
vtrans(p
->p_tracep
, TRACE
);
#define FPSIZE (sizeof (struct file *))
ALLOC_OFILES(filed
.fd_lastfile
);
if (filed
.fd_nfiles
> NDFILE
) {
if (!KVM_READ(filed
.fd_ofiles
, ofiles
,
filed
.fd_lastfile
* FPSIZE
)) {
"can't read file structures at %x for pid %d\n",
bcopy(filed0
.fd_dfiles
, ofiles
, filed
.fd_lastfile
* FPSIZE
);
bcopy(filed
.fd_ofile
, ofiles
, MIN(filed
.fd_lastfile
, NDFILE
) * FPSIZE
);
last
= filed
.fd_lastfile
;
if ((last
> NDFILE
) && !KVM_READ(filed
.fd_moreofiles
, &ofiles
[NDFILE
],
(last
- NDFILE
) * FPSIZE
)) {
dprintf(stderr
, "can't read rest of files at %x for pid %d\n",
filed
.fd_moreofiles
, Pid
);
for (i
= 0; i
< filed
.fd_lastfile
; i
++) {
if (!KVM_READ(ofiles
[i
], &file
, sizeof (struct file
))) {
dprintf(stderr
, "can't read file %d at %x for pid %d\n",
if (file
.f_type
== DTYPE_VNODE
)
vtrans((struct vnode
*)file
.f_data
, i
);
else if (file
.f_type
== DTYPE_SOCKET
) {
socktrans((struct socket
*)file
.f_data
, i
);
"unknown file type %d for file %d of pid %d\n",
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",
if (vn
.v_type
== VNON
|| vn
.v_tag
== VT_NON
)
else if (vn
.v_type
== VBAD
)
sprintf(badtype
= unknown
, "?(%x)", vn
.v_tag
);
for (d
= devs
; d
!= NULL
; d
= d
->next
)
if (d
->fsid
== fst
.fsid
) {
if (d
->ino
== fst
.fileid
) {
if (fsmatch
== 0 || (filename
== NULL
&& fsflg
== 0))
(void)printf(" - - %10s -\n", badtype
);
(void)printf(" %2d,%-2d", major(fst
.fsid
), minor(fst
.fsid
));
(void)printf(" %-8s", getmnton(vn
.v_mount
));
(void)sprintf(mode
, "%o", fst
.mode
);
(void)printf(" %6d %10s", fst
.fileid
, mode
);
if (nflg
|| ((name
= devname(fst
.rdev
, vn
.v_type
== VCHR
?
S_IFCHR
: S_IFBLK
)) == NULL
))
printf(" %2d,%-2d", major(fst
.rdev
), minor(fst
.rdev
));
printf(" %6d", fst
.size
);
struct inode
*ip
= VTOI(vp
);
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
;
register struct nfsnode
*np
= VTONFS(vp
);
fsp
->fsid
= np
->n_vattr
.va_fsid
;
fsp
->fileid
= np
->n_vattr
.va_fileid
;
fsp
->rdev
= np
->n_vattr
.va_rdev
;
mode
= (mode_t
)np
->n_vattr
.va_mode
;
static struct mount mount
;
char mntonname
[MNAMELEN
];
register struct mtab
*mt
;
for (mt
= mhead
; mt
!= NULL
; mt
= mt
->next
)
if (!KVM_READ(m
, &mount
, sizeof(struct mount
))) {
fprintf(stderr
, "can't read mount table at %x\n", m
);
if ((mt
= malloc(sizeof (struct mtab
))) == NULL
) {
fprintf(stderr
, "fstat: %s\n", strerror(errno
));
bcopy(&mount
.mnt_stat
.f_mntonname
[0], &mt
->mntonname
[0], MNAMELEN
);
static char *stypename
[] = {
char dname
[32], *strcpy();
if (!KVM_READ(sock
, &so
, sizeof(struct socket
))) {
dprintf(stderr
, "can't read sock at %x\n", sock
);
/* 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
);
if (!KVM_READ(proto
.pr_domain
, &dom
, sizeof(struct domain
))) {
dprintf(stderr
, "can't read domain at %x\n", proto
.pr_domain
);
kvm_read(dom
.dom_name
, dname
, sizeof(dname
) - 1)) < 0) {
dprintf(stderr
, "can't read domain name at %x\n",
if ((u_short
)so
.so_type
> STYPEMAX
)
printf("* %s ?%d", dname
, so
.so_type
);
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.
getinetproto(proto
.pr_protocol
);
if (proto
.pr_protocol
== IPPROTO_TCP
) {
if (kvm_read(so
.so_pcb
, &inpcb
,
!= sizeof(struct inpcb
)) {
"can't read inpcb at %x\n",
printf(" %x", (int)inpcb
.inp_ppcb
);
printf(" %x", (int)so
.so_pcb
);
/* print address of pcb and connected pcb */
printf(" %x", (int)so
.so_pcb
);
if (kvm_read(so
.so_pcb
, &unpcb
,
sizeof(struct unpcb
)) != sizeof(struct unpcb
)){
dprintf(stderr
, "can't read unpcb at %x\n",
if (!(so
.so_state
& SS_CANTRCVMORE
))
if (!(so
.so_state
& SS_CANTSENDMORE
))
printf(" %s %x", shoconn
,
/* print protocol number and socket address */
printf(" %d %x", proto
.pr_protocol
, (int)sock
);
* print name of protocol number
if (stat(filename
, &statbuf
)) {
fprintf(stderr
, "fstat: %s: %s\n", strerror(errno
),
if ((cur
= malloc(sizeof(DEVS
))) == NULL
) {
fprintf(stderr
, "fstat: %s\n", strerror(errno
));
cur
->ino
= statbuf
.st_ino
;
cur
->fsid
= statbuf
.st_dev
& 0xffff;
"usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");