* Copyright (c) 1987 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1987 Regents of the University of California.\n\
static char sccsid
[] = "@(#)fstat.c 5.5 (Berkeley) %G%";
#include <sys/socketvar.h>
#include <netinet/in_pcb.h>
# define i_number g_number
#define vprintf if (vflg) printf
struct proc proc
[8], *mproc
; /* 8 = a few, for less syscalls */
struct pte
*Usrptma
, *usrpt
;
char upages
[UPAGES
][NBPG
];
static int nproc
, nswap
, kmem
, mem
, swap
, uid
, pid
;
static int uflg
, fflg
, vflg
, pflg
;
static char *kmemf
= "kmem",
char *emalloc(), *getinetproto();
while ((ch
= getopt(argc
, argv
, "p:u:v")) != EOF
)
if (pflg
++ || ((pid
= atoi(optarg
)) <= 0)) {
if ((uid
= getuname(optarg
)) < 0) {
fprintf(stderr
, "%s: unknown user\n", optarg
);
for (argv
+= optind
; *argv
; ++argv
) {
printf("USER\t CMD\t PID FD\tDEVICE\tINODE\t SIZE\tTYPE\n");
procp
= lgetw((off_t
)nl
[X_PROC
].n_value
);
nproc
= (int)lgetw((off_t
)nl
[X_NPROC
].n_value
);
for (i
= 0; i
< nproc
; i
+= 8) {
(void)lseek(kmem
, (off_t
)procp
, 0);
j
*= sizeof(struct proc
);
if (read(kmem
, (char *)proc
, j
) != j
)
cantread("proc table", kmemf
);
for (j
= j
/ sizeof(struct proc
) - 1; j
>= 0; j
--) {
(void)lseek(kmem
, (off_t
)loc
, L_SET
);
if (read(kmem
, (char *) &word
, sizeof(word
)) != sizeof(word
))
vprintf("error reading kmem at %lx\n", loc
);
kmem
= open(kmemf
, O_RDONLY
, 0);
mem
= open(memf
, O_RDONLY
, 0);
swap
= open(swapf
, O_RDONLY
, 0);
if (nlist(nlistf
, nl
) == -1 || !nl
[0].n_type
) {
fprintf(stderr
, "%s: No namelist\n", nlistf
);
Usrptma
= (struct pte
*)nl
[X_USRPTMA
].n_value
;
usrpt
= (struct pte
*)nl
[X_USRPT
].n_value
;
(void)lseek(kmem
, (off_t
)nl
[X_NSWAP
].n_value
, L_SET
);
if (read(kmem
, (char *)&nswap
, sizeof(nswap
)) != sizeof(nswap
)) {
cantread("nswap", kmemf
);
vprintf("fstat: error reading %s from %s", what
, fromwhat
);
struct passwd
*getpwuid();
if (uflg
&& mproc
->p_uid
!= uid
)
if (pflg
&& mproc
->p_pid
!= pid
)
if (mproc
->p_stat
!= SZOMB
&& getu() == 0)
uname
= getpwuid(mproc
->p_uid
)->pw_name
;
struct pte
*pteaddr
, apte
;
struct pte arguutl
[UPAGES
+CLSIZE
];
size
= sizeof(struct user
);
if ((mproc
->p_flag
& SLOAD
) == 0) {
(void)lseek(swap
, (off_t
)dtob(mproc
->p_swaddr
), L_SET
);
if (read(swap
, (char *)&user
.user
, size
) != size
) {
fprintf(stderr
, "fstat: cant read u for pid %d from %s\n",
pteaddr
= &Usrptma
[btokmx(mproc
->p_p0br
) + mproc
->p_szpt
- 1];
(void)lseek(kmem
, (off_t
)pteaddr
, L_SET
);
if (read(kmem
, (char *)&apte
, sizeof(apte
)) != sizeof(apte
)) {
printf("fstat: cant read indir pte to get u for pid %d from %s\n",
(void)lseek(mem
, (off_t
)ctob(apte
.pg_pfnum
+1) - (UPAGES
+CLSIZE
)
* sizeof(struct pte
), L_SET
);
if (read(mem
, (char *)arguutl
, sizeof(arguutl
)) != sizeof(arguutl
)) {
printf("fstat: cant read page table for u of pid %d from %s\n",
ncl
= (size
+ NBPG
*CLSIZE
- 1) / (NBPG
*CLSIZE
);
(void)lseek(mem
, (off_t
)ctob(arguutl
[CLSIZE
+i
].pg_pfnum
), L_SET
);
if (read(mem
, user
.upages
[i
], CLSIZE
*NBPG
) != CLSIZE
*NBPG
) {
printf("fstat: cant read page %u of u of pid %d from %s\n",
arguutl
[CLSIZE
+i
].pg_pfnum
, mproc
->p_pid
, memf
);
(void)lseek(kmem
, (off_t
)mproc
->p_textp
, L_SET
);
if (read(kmem
, (char *) &text
, sizeof(text
)) != sizeof(text
)) {
cantread("text table", kmemf
);
itrans(DTYPE_INODE
, text
.x_iptr
, TEXT
);
#define UNK 0 /* unknown */
struct inode
*g
; /* if ftype is inode */
(void)lseek(kmem
, (off_t
)g
, L_SET
);
if (read(kmem
, (char *)&inode
, sizeof(inode
)) != sizeof(inode
)) {
vprintf("error %d reading inode at %x from kmem\n", errno
, (int)g
);
if (fflg
&& !devmatch(idev
, inode
.i_number
))
else if (mproc
->p_pid
== 2)
printf("%-8.8s %-10.10s %5d ", uname
, comm
, mproc
->p_pid
);
printf("* (deallocated)\n");
type
= itype(inode
.i_mode
); /* determine inode type */
printf("\t%2d, %2d\t%5lu\t%6ld\t%3s\n", major(inode
.i_dev
),
minor(inode
.i_dev
), inode
.i_number
,
type
== SOC
? 0 : inode
.i_size
, itypename
[type
]);
socktrans((struct socket
*)g
);
printf("* (fifo / named pipe)\n");
printf("* (unknown file type)\n");
for (d
= d
->next
; d
; d
= d
->next
)
if (d
->dev
== idev
&& (!d
->inum
|| d
->inum
== inum
))
static char *stypename
[] = {
char c
, *cp
, *stype
, *strcpy(), *strcat();
char dname
[32]; /* domain name, e.g. "inet" */
(void)lseek(kmem
, (off_t
)sock
, L_SET
);
if (read(kmem
, (char *)&so
, sizeof(struct socket
))
!= sizeof(struct socket
)) {
vprintf("error %d reading socket at %x from kmem\n", errno
, (int)sock
);
/* fill in protosw entry */
(void)lseek(kmem
, (off_t
)so
.so_proto
, L_SET
);
if (read(kmem
, (char *)&proto
, sizeof(struct protosw
))
!= sizeof(struct protosw
)) {
vprintf("error %d reading protosw at %x from kmem\n", errno
, (int)so
.so_proto
);
(void)lseek(kmem
, (off_t
)proto
.pr_domain
, L_SET
);
if (read(kmem
, (char *)&dom
, sizeof(struct domain
))
!= sizeof(struct domain
)) {
vprintf("error %d reading domain at %x from kmem\n", errno
, (int)proto
.pr_domain
);
(void)lseek(kmem
, (off_t
)dom
.dom_name
, L_SET
);
/* 30 leaves room for null byte */
for (cp
= dname
, i
= 0; i
< 30; i
++, cp
++) {
if (read(kmem
, (char *)&c
, sizeof(char)) != sizeof(char)) {
vprintf("error %d reading char at %x from kmem\n", errno
, (int)(dom
.dom_name
+i
));
/* kludge "internet" --> "inet" for brevity */
if (dom
.dom_family
== AF_INET
)
(void)strcpy(dname
, "inet");
if (so
.so_type
< 1 || so
.so_type
> STYPEMAX
) {
(void)sprintf(stype
, "unk%d", so
.so_type
);
stype
= stypename
[so
.so_type
];
/* print sock type, sock state, and domain name */
printf("* (%s %s %x", dname
, stype
, so
.so_state
);
* protocol specific formating
* 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.
if (dom
.dom_family
== AF_INET
) {
/* print name of protocol number */
printf(" %s", getinetproto(proto
.pr_protocol
));
if (proto
.pr_protocol
== IPPROTO_TCP
) {
(void)lseek(kmem
, (off_t
)so
.so_pcb
, L_SET
);
if (read(kmem
, (char *)&inpcb
, sizeof(struct inpcb
))
!= sizeof(struct inpcb
)){
vprintf("error %d reading inpcb at %x from kmem\n",
printf(" %x", (int)inpcb
.inp_ppcb
);
printf(" %x", (int)so
.so_pcb
);
else if (dom
.dom_family
== AF_UNIX
) {
/* print address of pcb and connected pcb */
printf(" %x", (int)so
.so_pcb
);
(void)lseek(kmem
, (off_t
)so
.so_pcb
, L_SET
);
if (read(kmem
, (char *)&unpcb
, sizeof(struct unpcb
))
!= sizeof(struct unpcb
)){
vprintf("error %d reading unpcb at %x from kmem\n",
char shoconn
[4]; *shoconn
= 0;
if (!(so
.so_state
& SS_CANTRCVMORE
))
(void)strcat(shoconn
, "<");
(void)strcat(shoconn
, "-");
if (!(so
.so_state
& SS_CANTSENDMORE
))
(void)strcat(shoconn
, ">");
printf(" %s %x", shoconn
, (int)unpcb
.unp_conn
);
else /* print protocol number and socket address */
printf(" %d %x", proto
.pr_protocol
, (int)sock
);
(void)sprintf(cp
= emalloc(16), "%d", number
);
if (!(cp
= (char *)malloc((u_int
)size
))) {
fprintf(stderr
, "fstat: out of space.\n");
itrans(DTYPE_INODE
, user
.user
.u_cdir
, WD
);
for (i
= 0; i
< NOFILE
; i
++) {
if (user
.user
.u_ofile
[i
] == 0)
(void)lseek(kmem
, (off_t
)user
.user
.u_ofile
[i
], L_SET
);
if (read(kmem
, (char *)&lfile
, sizeof(lfile
))
itrans(lfile
.f_type
, (struct inode
*)lfile
.f_data
, i
);
fputs("usage: fstat [-v] [-u user] [-p pid] [filename ...]\n", stderr
);
struct passwd
*passwd
, *getpwnam();
return((passwd
= getpwnam(arg_uname
)) ? passwd
->pw_uid
: -1);
if (stat(filename
, &statbuf
)) {
* if file is block special, look for open files on it
if ((statbuf
.st_mode
& S_IFMT
) != S_IFBLK
) {
for (d
= oldd
= &devs
; d
; oldd
= d
, d
= d
->next
)
d
= (struct devs
*)emalloc(sizeof(struct devs
));