ec0c7150234ff83c484b888ef526d68782e1ae3d
* 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.43 (Berkeley) %G%";
#include <sys/socketvar.h>
#include <sys/kinfo_proc.h>
#include <sys/filedesc.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.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(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (len))
int ufs_filestat(), nfs_filestat();
void dofiles(), getinetproto(), socktrans();
register struct passwd
*passwd
;
struct kinfo_proc
*p
, *plast
;
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 */
* 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
)
if ((kd
= kvm_open(nlistf
, memf
, NULL
, O_RDONLY
, NULL
)) == NULL
) {
fprintf(stderr
, "fstat: %s\n", kvm_geterr(kd
));
if (kvm_nlist(kd
, nl
) != 0) {
fprintf(stderr
, "fstat: no namelist: %s\n", kvm_geterr(kd
));
if ((p
= kvm_getprocs(kd
, what
, arg
, &cnt
)) == NULL
) {
fprintf(stderr
, "fstat: %s\n", kvm_geterr(kd
));
"USER CMD PID FD DEV INUM MODE SZ|DV");
"USER CMD PID FD MOUNT INUM MODE SZ|DV");
if (checkfile
&& fsflg
== 0)
for (plast
= &p
[cnt
]; p
< plast
; ++p
) {
if (p
->kp_proc
.p_stat
== SZOMB
)
#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
* print open files attributed to this process
#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);
if (!KVM_READ(p
->p_fd
, &filed0
, sizeof (filed0
))) {
dprintf(stderr
, "can't read filedesc at %x for pid %d\n",
* root directory vnode, if one
vtrans(filed
.fd_rdir
, RDIR
);
* current working directory vnode
vtrans(filed
.fd_cdir
, CDIR
);
vtrans(p
->p_tracep
, TRACE
);
#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
)) {
"can't read file structures at %x for pid %d\n",
bcopy(filed0
.fd_dfiles
, ofiles
, (filed
.fd_lastfile
+1) * FPSIZE
);
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
)
if (!ufs_filestat(&vn
, &fst
))
if (!ufs_filestat(&vn
, &fst
))
if (!nfs_filestat(&vn
, &fst
))
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
);
if (!KVM_READ(VTOI(vp
), &inode
, sizeof (inode
))) {
dprintf(stderr
, "can't read inode at %x for pid %d\n",
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
;
if (!KVM_READ(VTONFS(vp
), &nfsnode
, sizeof (nfsnode
))) {
dprintf(stderr
, "can't read nfsnode at %x for pid %d\n",
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
;
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
);
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",
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(kd
, (u_long
)so
.so_pcb
,
(char *)&inpcb
, sizeof(struct 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(kd
, (u_long
)so
.so_pcb
, (char *)&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", filename
, 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");