* Copyright (c) 1987 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1987 Regents of the University of California.\n\
static char sccsid
[] = "@(#)fstat.c 5.13 (Berkeley) 6/18/88";
#include <sys/socketvar.h>
#include <netinet/in_pcb.h>
# define i_number g_number
#define N_KMEM "/dev/kmem"
#define N_SWAP "/dev/drum"
static struct nlist nl
[] = {
struct pte
*Usrptma
, *usrpt
;
char upages
[UPAGES
][NBPG
];
static int kmem
, mem
, nproc
, swap
;
register struct passwd
*passwd
;
register int pflg
, pid
, uflg
, uid
;
struct passwd
*getpwnam(), *getpwuid();
while ((ch
= getopt(argc
, argv
, "p:u:v")) != EOF
)
fputs("fstat: -p option requires a process id.\n", stderr
);
if (!(passwd
= getpwnam(optarg
))) {
fprintf(stderr
, "%s: unknown uid\n", optarg
);
case 'v': /* undocumented: print read error messages */
if (!fflg
) /* file(s) specified, but none accessable */
if (nlist(N_UNIX
, nl
) == -1 || !nl
[0].n_type
) {
fprintf(stderr
, "%s: No namelist\n", N_UNIX
);
Usrptma
= (struct pte
*)nl
[X_USRPTMA
].n_value
;
usrpt
= (struct pte
*) nl
[X_USRPT
].n_value
;
nproc
= (int)lgetw((off_t
)nl
[X_NPROC
].n_value
);
(void)lseek(kmem
, lgetw((off_t
)nl
[X_PROC
].n_value
), L_SET
);
size
= nproc
* sizeof(struct proc
);
if ((mproc
= (struct proc
*)malloc((u_int
)size
)) == NULL
) {
fprintf(stderr
, "fstat: out of space.\n");
if (read(kmem
, (char *)mproc
, size
) != size
)
rerr1("proc table", N_KMEM
);
printf("USER\t CMD\t PID FD\tDEVICE\tINODE\t SIZE TYPE%s\n",
for (; nproc
--; ++mproc
) {
if (pflg
&& mproc
->p_pid
!= pid
)
uname
= (passwd
= getpwuid(mproc
->p_uid
)) ?
passwd
->pw_name
: "unknown";
if (mproc
->p_stat
!= SZOMB
&& getu() == 0)
struct pte
*pteaddr
, apte
;
struct pte arguutl
[UPAGES
+CLSIZE
];
if ((mproc
->p_flag
& SLOAD
) == 0) {
(void)lseek(swap
, (off_t
)dtob(mproc
->p_swaddr
), L_SET
);
if (read(swap
, (char *)&user
.user
, sizeof(struct user
))
!= sizeof(struct user
)) {
fprintf(stderr
, "fstat: can't read u for pid %d from %s\n", mproc
->p_pid
, N_SWAP
);
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: can't read indir pte to get u for pid %d from %s\n", mproc
->p_pid
, N_SWAP
);
(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: can't read page table for u of pid %d from %s\n", mproc
->p_pid
, N_KMEM
);
ncl
= (sizeof(struct user
) + 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: can't read page %u of u of pid %d from %s\n", arguutl
[CLSIZE
+i
].pg_pfnum
, mproc
->p_pid
, N_MEM
);
(void)lseek(kmem
, (off_t
)mproc
->p_textp
, L_SET
);
if (read(kmem
, (char *) &text
, sizeof(text
)) != sizeof(text
)) {
rerr1("text table", N_KMEM
);
itrans(DTYPE_INODE
, text
.x_iptr
, TEXT
);
struct inode
*g
; /* if ftype is inode */
char *name
= (char *)NULL
; /* set by devmatch() on a match */
(void)lseek(kmem
, (off_t
)g
, L_SET
);
if (read(kmem
, (char *)&inode
, sizeof(inode
)) != sizeof(inode
)) {
rerr2(errno
, (int)g
, "inode");
if (fflg
&& !devmatch(idev
, inode
.i_number
, &name
))
else if (mproc
->p_pid
== 2)
printf("%-8.8s %-10.10s %5d ", uname
, comm
, mproc
->p_pid
);
printf("* (deallocated)\n");
printf("\t%2d, %2d\t%5lu\t%6ld\t%3s %s\n", major(inode
.i_dev
),
minor(inode
.i_dev
), inode
.i_number
,
inode
.i_mode
== IFSOCK
? 0 : inode
.i_size
,
itype(inode
.i_mode
), name
? name
: "");
socktrans((struct socket
*)g
);
printf("* (fifo / named pipe)\n");
printf("* (unknown file type)\n");
static char *stypename
[] = {
char dname
[32], *strcpy();
(void)lseek(kmem
, (off_t
)sock
, L_SET
);
if (read(kmem
, (char *)&so
, sizeof(struct socket
))
!= sizeof(struct socket
)) {
rerr2(errno
, (int)sock
, "socket");
/* 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
)) {
rerr2(errno
, (int)so
.so_proto
, "protosw");
(void)lseek(kmem
, (off_t
)proto
.pr_domain
, L_SET
);
if (read(kmem
, (char *)&dom
, sizeof(struct domain
))
!= sizeof(struct domain
)) {
rerr2(errno
, (int)proto
.pr_domain
, "domain");
* kludge "internet" --> "inet" for brevity
if (dom
.dom_family
== AF_INET
)
(void)strcpy(dname
, "inet");
(void)lseek(kmem
, (off_t
)dom
.dom_name
, L_SET
);
if ((len
= read(kmem
, dname
, sizeof(dname
) - 1)) < 0) {
rerr2(errno
, (int)dom
.dom_name
, "char");
if ((u_short
)so
.so_type
> STYPEMAX
)
printf("* (%s unk%d %x", dname
, so
.so_type
, so
.so_state
);
printf("* (%s %s %x", 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
) {
(void)lseek(kmem
, (off_t
)so
.so_pcb
, L_SET
);
if (read(kmem
, (char *)&inpcb
, sizeof(struct inpcb
))
!= sizeof(struct inpcb
)){
rerr2(errno
, (int)so
.so_pcb
, "inpcb");
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
);
(void)lseek(kmem
, (off_t
)so
.so_pcb
, L_SET
);
if (read(kmem
, (char *)&unpcb
, sizeof(struct unpcb
))
!= sizeof(struct unpcb
)){
rerr2(errno
, (int)so
.so_pcb
, "unpcb");
if (!(so
.so_state
& SS_CANTRCVMORE
))
if (!(so
.so_state
& SS_CANTSENDMORE
))
printf(" %s %x", shoconn
, (int)unpcb
.unp_conn
);
/* print protocol number and socket address */
printf(" %d %x", proto
.pr_protocol
, (int)sock
);
* print name of protocol number
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
);
devmatch(idev
, inum
, name
)
for (d
= devs
; d
; d
= d
->next
)
if (d
->dev
== idev
&& (d
->inum
== 0 || d
->inum
== inum
)) {
if (stat(filename
, &statbuf
)) {
if ((cur
= (DEVS
*)malloc(sizeof(DEVS
))) == NULL
) {
fprintf(stderr
, "fstat: out of space.\n");
/* if file is block special, look for open files on it */
if ((statbuf
.st_mode
& S_IFMT
) != S_IFBLK
) {
cur
->inum
= statbuf
.st_ino
;
cur
->dev
= statbuf
.st_dev
;
cur
->dev
= statbuf
.st_rdev
;
if ((kmem
= open(N_KMEM
, O_RDONLY
, 0)) < 0) {
if ((mem
= open(N_MEM
, O_RDONLY
, 0)) < 0) {
if ((swap
= open(N_SWAP
, O_RDONLY
, 0)) < 0) {
printf("fstat: error reading %s from %s", what
, fromwhat
);
rerr2(err
, address
, what
)
printf("error %d reading %s at %x from kmem\n", errno
, what
, address
);
(void)lseek(kmem
, (off_t
)loc
, L_SET
);
if (read(kmem
, (char *)&word
, sizeof(word
)) != sizeof(word
))
rerr2(errno
, (int)loc
, "word");
fputs("usage: fstat [-v] [-u user] [-p pid] [filename ...]\n", stderr
);