* 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.1 (Berkeley) %G%";
#include <sys/socketvar.h>
#include <netinet/in_pcb.h>
# define i_number g_number
#define vprintf if (vflg) printf
int pcbpf
, nswap
, kmem
, mem
, swap
, uid
, pid
;
int uflg
, fflg
, inum
, Mdev
, mdev
, special
, vflg
, nproc
, pflg
;
#define clear(x) ((int)x & 0x7fffffff)
struct proc proc
[8], *mproc
; /* 8 = a few, for less syscalls */
struct pte
*Usrptma
, *usrpt
;
int paduser1
; /* avoid hardware mem clobbering botch */
char upages
[UPAGES
][NBPG
];
int paduser2
; /* avoid hardware mem clobbering botch */
char *kmemf
, *memf
, *swapf
, *nlistf
;
if (strcmp(*argv
, "-v") == 0) {
if (strcmp(*argv
, "-u") == 0) {
if ((uid
= getuname(*(++argv
))) < 0) {
fprintf(stderr
, "%s: unknown user\n", *argv
);
if (strcmp(*argv
, "-f") == 0) {
if ((dev
= getfname(*(++argv
))) < 0) {
if (strcmp(*argv
, "-p") == 0) {
if (pflg
++ || ((pid
= Atoi(*(++argv
))) <= 0)) {
/* admit missing -u, -f, -p */
/* it's an expert system! */
if ((pid
= Atoi(*argv
)) > 0) {
if ((dev
= getfname(*argv
)) < 0) {
if ((uid
= getuname(*argv
)) < 0) {
"%s: unknown user\n", *argv
);
/* !uflg && !fflg -- which is it? */
if ((dev
= getfname(*argv
)) >= 0)
fflg
++; /* could be a file */
if ((uid
= getuname(*argv
)) >= 0)
uflg
++; /* could be a user */
if ((!uflg
^ !fflg
) == 0)
usage(); /* could be either/neither */
printf("user\t cmd\t pid fd\tdevice\tinode\t size\ttype\n");
procp
= getw((off_t
) nl
[X_PROC
].n_value
);
nproc
= getw((off_t
) nl
[X_NPROC
].n_value
);
for (i
=0; i
<nproc
; i
+= 8) {
lseek(kmem
, (long) 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
--) {
lseek(kmem
, (long) loc
, 0);
if (read(kmem
, (char *) &word
, sizeof (word
)) != sizeof (word
))
vprintf("error reading kmem at %x\n", loc
);
fprintf(stderr
, "%s: No namelist\n", nlistf
);
Usrptma
= (struct pte
*) nl
[X_USRPTMA
].n_value
;
usrpt
= (struct pte
*) nl
[X_USRPT
].n_value
;
lseek(kmem
, (long) nl
[X_NSWAP
].n_value
, 0);
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
, (long)dtob(mproc
->p_swaddr
), 0);
if (read(swap
, (char *)&user
.user
, size
) != size
) {
fprintf(stderr
, "ps: cant read u for pid %d from %s\n",
pteaddr
= &Usrptma
[btokmx(mproc
->p_p0br
) + mproc
->p_szpt
- 1];
klseek(kmem
, (long)pteaddr
, 0);
if (read(kmem
, (char *)&apte
, sizeof(apte
)) != sizeof(apte
)) {
printf("fstat: cant read indir pte to get u for pid %d from %s\n",
(long)ctob(apte
.pg_pfnum
+1) - (UPAGES
+CLSIZE
) * sizeof (struct pte
),
if (read(mem
, (char *)arguutl
, sizeof(arguutl
)) != sizeof(arguutl
)) {
printf("fstat: cant read page table for u of pid %d from %s\n",
if (arguutl
[0].pg_fod
== 0 && arguutl
[0].pg_pfnum
)
argaddr
= ctob(arguutl
[0].pg_pfnum
);
pcbpf
= arguutl
[CLSIZE
].pg_pfnum
;
ncl
= (size
+ NBPG
*CLSIZE
- 1) / (NBPG
*CLSIZE
);
klseek(mem
, (long)ctob(arguutl
[CLSIZE
+i
].pg_pfnum
), 0);
if (read(mem
, user
.upages
[i
], CLSIZE
*NBPG
) != CLSIZE
*NBPG
) {
printf("fstat: cant read page %d of u of pid %d from %s\n",
arguutl
[CLSIZE
+i
].pg_pfnum
, mproc
->p_pid
, memf
);
lseek(kmem
, (long) mproc
->p_textp
, 0);
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 */
lseek(kmem
, (long) g
, 0);
if (read(kmem
, (char *) &inode
, sizeof(inode
))
vprintf("error %d reading inode at %x from kmem\n", errno
, g
);
if (fflg
&& major(idev
) != Mdev
)
if (fflg
&& minor(idev
) != mdev
)
if (inum
&& inode
.i_number
!= inum
)
else if (mproc
->p_pid
== 2)
printf("%-8.8s %-10.10s %5d ", uname
, comm
, mproc
->p_pid
);
printf("* (deallocated)\n");
if (ftype
== DTYPE_INODE
) {
type
= itype(inode
.i_mode
); /* determine inode type */
printf("\t%2d, %2d\t%5d\t%6d\t%3s\n", major(inode
.i_dev
), minor(inode
.i_dev
),
inode
.i_number
, type
== SOC
?0:inode
.i_size
, itypename
[type
]);
else if (ftype
== DTYPE_SOCKET
) {
socktrans((struct socket
*)g
);
else if (ftype
== DTYPE_PORT
) {
printf("* (fifo / named pipe)\n");
printf("* (unknown file type)\n");
char dname
[32]; /* domain name, e.g. "inet" */
lseek(kmem
, (long) sock
, 0);
if (read(kmem
, (char *) &so
, sizeof(struct socket
))
!= sizeof(struct socket
)){
vprintf("error %d reading socket at %x from kmem\n", errno
, sock
);
/* fill in protosw entry */
lseek(kmem
, (long) so
.so_proto
, 0);
if (read(kmem
, (char *) &proto
, sizeof(struct protosw
))
!= sizeof(struct protosw
)){
vprintf("error %d reading protosw at %x from kmem\n", errno
, so
.so_proto
);
lseek(kmem
, (long) proto
.pr_domain
, 0);
if (read(kmem
, (char *) &dom
, sizeof(struct domain
))
!= sizeof(struct domain
)){
vprintf("error %d reading domain at %x from kmem\n", errno
, proto
.pr_domain
);
lseek(kmem
, (long) dom
.dom_name
, 0);
for (cp
=dname
, i
=0; i
< 30; i
++, cp
++) { /* 30 leaves room for null byte */
if (read(kmem
, (char *)&c
, sizeof(char)) != sizeof(char)) {
vprintf("error %d reading char at %x from kmem\n", errno
, dom
.dom_name
+i
);
/* kludge "internet" --> "inet" for brevity */
if (dom
.dom_family
== AF_INET
)
if (so
.so_type
< 1 || so
.so_type
> STYPEMAX
)
stype
= (char *)sprintf(emalloc(10),"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
) {
lseek(kmem
, (long) so
.so_pcb
, 0);
if (read(kmem
, (char *) &inpcb
, sizeof(struct inpcb
))
!= sizeof(struct inpcb
)){
vprintf("error %d reading inpcb at %x from kmem\n",
printf(" %x", inpcb
.inp_ppcb
);
printf(" %x", so
.so_pcb
);
} else if (dom
.dom_family
== AF_UNIX
) {
/* print address of pcb and connected pcb */
printf(" %x", so
.so_pcb
);
lseek(kmem
, (long) so
.so_pcb
, 0);
if (read(kmem
, (char *) &unpcb
, sizeof(struct unpcb
))
!= sizeof(struct unpcb
)){
vprintf("error %d reading unpcb at %x from kmem\n",
printf(" -> %x", unpcb
.unp_conn
);
/* print protocol number and socket address */
printf(" %d %x", proto
.pr_protocol
, sock
);
default: return((char *)sprintf(emalloc(16),"%d",number
));
cp
= (char *)malloc(size
);
fprintf(stderr
,"Out of space.\n");
itrans(DTYPE_INODE
, u
.u_cdir
, WD
);
for (i
= 0; i
< NOFILE
; i
++) {
lseek(kmem
, (long) u
.u_ofile
[i
], 0);
if (read(kmem
, (char *) &file
, sizeof(file
)) != sizeof(file
)) {
/*printf("flag: %x count: %x ",file.f_flag, file.f_count);
itrans(file
.f_type
, file
.f_data
, i
);
fputs("usage: fstat [-u user] [-f filename] [-p pid]\n", stderr
);
struct passwd
*passwd
, *getpwnam();
if ((passwd
= getpwnam(uname
)) == NULL
)
if (stat(filename
, &statbuf
) != 0)
* if file is block special, look for open files on it
if ((statbuf
.st_mode
& S_IFMT
) != S_IFBLK
) {
while(*p
>= '0' && *p
<= '9')
sizeSysmap
= nl
[SSYSSIZE
].n_value
* sizeof( struct pte
);
Sysmap
= (struct pte
*)calloc( sizeSysmap
, 1);
lseek( kmem
, clear( nl
[SSYSMAP
].n_value
), 0);
if( read( kmem
, Sysmap
, sizeSysmap
) != sizeSysmap
)
printf( "Cant read system page table\n");
if( kflg
&& (loc
&0x80000000))
{/* do mapping for kernel virtual addresses */
ptep
= &Sysmap
[btop(loc
)];
if( (char *)ptep
- (char *)Sysmap
> sizeSysmap
)
printf( "no system pte for %s\n", loc
);
printf( "system pte invalid for %x\n", loc
);
loc
= (off_t
)((loc
&PGOFSET
) + ptob(ptep
->pg_pfnum
));
(void) lseek(fd
, (long)loc
, off
);