* 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.25 (Berkeley) %G%";
#include <sys/socketvar.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
register struct passwd
*passwd
;
int what
= KINFO_PROC_ALL
, arg
= 0;
struct passwd
*getpwnam(), *getpwuid();
while ((ch
= getopt(argc
, argv
, "p:u:fnv")) != EOF
)
fputs("fstat: -p option requires a process id.\n", stderr
);
if (!(passwd
= getpwnam(optarg
))) {
fprintf(stderr
, "%s: unknown uid\n",
if (!checkfile
) /* file(s) specified, but none accessable */
if (fsflg
&& !checkfile
) {
/* -f with no files means use wd */
/* modify the following to make work on dead kernels */
if (kvm_openfiles(NULL
, NULL
, 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());
fputs("USER CMD PID FD DEV INUM MODE SZ|DV", stdout
);
fputs("USER CMD PID FD MOUNT INUM MODE SZ|DV", stdout
);
if (checkfile
&& fsflg
== 0)
fputs(" NAME\n", stdout
);
while ((p
= kvm_nextproc()) != NULL
) {
#define PREFIX(i) printf("%-8.8s %-8.8s %5d", Uname, Comm, Pid); \
fputs(" text", stdout); \
fputs(" root", stdout); \
* print open files attributed to this process
struct user
*up
= kvm_getu(p
);
extern char *user_from_uid();
Uname
= user_from_uid(p
->p_uid
, 0);
dprintf(stderr
, "can't read u for pid %d\n", Pid
);
* root directory vnode, if one
vtrans(up
->u_rdir
, RDIR
);
kvm_read(&(p
->p_textp
->x_vptr
), &xvptr
,
sizeof (struct vnode
*)) == sizeof (struct vnode
*) &&
* current working directory vnode
vtrans(up
->u_cdir
, CDIR
);
vtrans(p
->p_tracep
, TRACE
);
for (i
= 0; i
<= up
->u_lastfile
; i
++) {
if (kvm_read(up
->u_ofile
[i
], &file
, sizeof (struct file
)) !=
dprintf(stderr
, "can't read file %d for pid %d\n",
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
);
"unknown file type %d for file %d of pid %d\n",
if (kvm_read((off_t
)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((off_t
)m
, &mount
, sizeof(struct mount
)) !=
fprintf(stderr
, "can't read mount table at %x\n", m
);
if ((mt
= (struct mtab
*)malloc(sizeof (struct mtab
))) == NULL
) {
fprintf(stderr
, "out of memory\n");
bcopy(&mount
.mnt_stat
.f_mntonname
[0], &mt
->mntonname
[0], MNAMELEN
);
static char *stypename
[] = {
char dname
[32], *strcpy();
if (kvm_read((off_t
)sock
, (char *)&so
, sizeof(struct socket
))
!= sizeof(struct socket
)) {
dprintf(stderr
, "can't read sock at %x\n", sock
);
/* fill in protosw entry */
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
);
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
);
* kludge "internet" --> "inet" for brevity
if (dom
.dom_family
== AF_INET
)
if ((len
= kvm_read((off_t
)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((off_t
)so
.so_pcb
, (char *)&inpcb
, sizeof(struct inpcb
))
!= sizeof(struct inpcb
)){
"can't read inpcb at %x\n", so
.so_pcb
);
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((off_t
)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", strerror(errno
),
if ((cur
= (DEVS
*)malloc(sizeof(DEVS
))) == NULL
) {
fprintf(stderr
, "fstat: out of space.\n");
cur
->ino
= statbuf
.st_ino
;
cur
->fsid
= statbuf
.st_dev
& 0xffff;
"usage: fstat [-u user] [-p pid] [filename ...]\n");