* Copyright (c) 1980, 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char copyright
[] =
"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)pstat.c 8.16 (Berkeley) %G%";
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <miscfs/union/union.h>
#include <nfs/nfsproto.h>
{ "_swapmap" }, /* list of free swap areas */
{ "_nswapmap" },/* size of the swap map */
{ "_swdevt" }, /* list of swap devices and sizes */
{ "_nswap" }, /* size of largest swap device */
{ "_nswdev" }, /* number of swap devices */
{ "_dmmax" }, /* maximum size of a swap block */
{ "_mountlist" }, /* address of head of mount list. */
#define NLMANDATORY FNL_MAXFILE /* names up to here are mandatory */
#define VM_NISWAP NLMANDATORY + 1
#define VM_NISWDEV NLMANDATORY + 2
#define SCONS NLMANDATORY + 3
#define SPTY NLMANDATORY + 4
#define SNPTY NLMANDATORY + 5
{ MNT_RDONLY
, "rdonly" },
{ MNT_SYNCHRONOUS
, "sync" },
{ MNT_NOEXEC
, "noexec" },
{ MNT_NOSUID
, "nosuid" },
{ MNT_EXRDONLY
, "exrdonly" },
{ MNT_EXPORTED
, "exported" },
{ MNT_DEFEXPORTED
, "defexported" },
{ MNT_EXPORTANON
, "exportanon" },
{ MNT_EXKERB
, "exkerb" },
{ MNT_ROOTFS
, "rootfs" },
{ MNT_UPDATE
, "update" },
{ MNT_UPDATE
, "update" },
{ MNT_DELEXPORT
, "delexport" },
{ MNT_RELOAD
, "reload" },
{ MNT_MPBUSY
, "mpbusy" },
{ MNT_MPWANT
, "mpwant" },
{ MNT_UNMOUNT
, "unmount" },
{ MNT_WANTRDWR
, "wantrdwr" },
#define SVAR(var) __STRING(var) /* to force expansion */
KGET1(idx, &var, sizeof(var), SVAR(var))
#define KGET1(idx, p, s, msg) \
KGET2(nl[idx].n_value, p, s, msg)
#define KGET2(addr, p, s, msg) \
if (kvm_read(kd, (u_long)(addr), p, s) != s) \
warnx("cannot read %s: %s", msg, kvm_geterr(kd))
#define KGETRET(addr, p, s, msg) \
if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
void filemode
__P((void));
int getfiles
__P((char **, int *));
getmnt
__P((struct mount
*));
kinfo_vnodes
__P((int *));
void mount_print
__P((struct mount
*));
void nfs_header
__P((void));
int nfs_print
__P((struct vnode
*));
void swapmode
__P((void));
void ttymode
__P((void));
void ttyprt
__P((struct tty
*, int));
void ttytype
__P((struct tty
*, char *, int, int));
void ufs_header
__P((void));
int ufs_print
__P((struct vnode
*));
void union_header
__P((void));
int union_print
__P((struct vnode
*));
void vnode_header
__P((void));
void vnode_print
__P((struct vnode
*, struct vnode
*));
void vnodemode
__P((void));
int fileflag
, swapflag
, ttyflag
, vnodeflag
;
char buf
[_POSIX2_LINE_MAX
];
fileflag
= swapflag
= ttyflag
= vnodeflag
= 0;
while ((ch
= getopt(argc
, argv
, "TM:N:finstv")) != EOF
)
case 'i': /* Backward compatibility. */
* 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_openfiles(nlistf
, memf
, NULL
, O_RDONLY
, buf
)) == 0)
errx(1, "kvm_openfiles: %s", buf
);
if ((ret
= kvm_nlist(kd
, nl
)) != 0) {
errx(1, "kvm_nlist: %s", kvm_geterr(kd
));
for (i
= quit
= 0; i
<= NLMANDATORY
; i
++)
warnx("undefined symbol: %s\n", nl
[i
].n_name
);
if (!(fileflag
| vnodeflag
| ttyflag
| swapflag
| totalflag
))
if (fileflag
|| totalflag
)
if (vnodeflag
|| totalflag
)
if (swapflag
|| totalflag
)
struct e_vnode
*e_vnodebase
, *endvnode
, *evp
;
struct mount
*maddr
, *mp
;
e_vnodebase
= loadvnodes(&numvnodes
);
(void)printf("%7d vnodes\n", numvnodes
);
endvnode
= e_vnodebase
+ numvnodes
;
(void)printf("%d active vnodes\n", numvnodes
);
for (evp
= e_vnodebase
; evp
< endvnode
; evp
++) {
if (vp
->v_mount
!= maddr
) {
if ((mp
= getmnt(vp
->v_mount
)) == NULL
)
if (!strcmp(ST
.f_fstypename
, "ufs") ||
!strcmp(ST
.f_fstypename
, "mfs"))
else if (!strcmp(ST
.f_fstypename
, "nfs"))
else if (!strcmp(ST
.f_fstypename
, "union"))
vnode_print(evp
->avnode
, vp
);
if (!strcmp(ST
.f_fstypename
, "ufs") ||
!strcmp(ST
.f_fstypename
, "mfs"))
else if (!strcmp(ST
.f_fstypename
, "nfs"))
else if (!strcmp(ST
.f_fstypename
, "union"))
(void)printf("ADDR TYP VFLAG USE HOLD");
(void)printf("%8x %s %5s %4d %4d",
avnode
, type
, flags
, vp
->v_usecount
, vp
->v_holdcnt
);
(void)printf(" FILEID IFLAG RDEV|SZ");
struct inode inode
, *ip
= &inode
;
char flagbuf
[16], *flags
= flagbuf
;
KGETRET(VTOI(vp
), &inode
, sizeof(struct inode
), "vnode's inode");
(void)printf(" %6d %5s", ip
->i_number
, flagbuf
);
type
= ip
->i_mode
& S_IFMT
;
if (S_ISCHR(ip
->i_mode
) || S_ISBLK(ip
->i_mode
))
if (usenumflag
|| ((name
= devname(ip
->i_rdev
, type
)) == NULL
))
(void)printf(" %2d,%-2d",
major(ip
->i_rdev
), minor(ip
->i_rdev
));
(void)printf(" %7s", name
);
(void)printf(" %7qd", ip
->i_size
);
(void)printf(" FILEID NFLAG RDEV|SZ");
struct nfsnode nfsnode
, *np
= &nfsnode
;
char flagbuf
[16], *flags
= flagbuf
;
KGETRET(VTONFS(vp
), &nfsnode
, sizeof(nfsnode
), "vnode's nfsnode");
if (flag
& NQNFSNONCACHE
)
(void)printf(" %6d %5s", VT
.va_fileid
, flagbuf
);
type
= VT
.va_mode
& S_IFMT
;
if (S_ISCHR(VT
.va_mode
) || S_ISBLK(VT
.va_mode
))
if (usenumflag
|| ((name
= devname(VT
.va_rdev
, type
)) == NULL
))
(void)printf(" %2d,%-2d",
major(VT
.va_rdev
), minor(VT
.va_rdev
));
(void)printf(" %7s", name
);
(void)printf(" %7qd", np
->n_size
);
(void)printf(" UPPER LOWER");
struct union_node unode
, *up
= &unode
;
KGETRET(VTOUNION(vp
), &unode
, sizeof(unode
), "vnode's unode");
(void)printf(" %8x %8x", up
->un_uppervp
, up
->un_lowervp
);
* Given a pointer to a mount structure in kernel space,
* read it in and return a usable pointer to it.
for (mt
= mhead
; mt
!= NULL
; mt
= mt
->next
)
if ((mt
= malloc(sizeof(struct mtab
))) == NULL
)
KGETRET(maddr
, &mt
->mount
, sizeof(struct mount
), "mount table");
(void)printf("*** MOUNT %s %s on %s", ST
.f_fstypename
,
ST
.f_mntfromname
, ST
.f_mntonname
);
if (flags
= mp
->mnt_flag
) {
for (i
= 0; mnt_flags
[i
].m_flag
; i
++) {
if (flags
& mnt_flags
[i
].m_flag
) {
(void)printf("%s%s", sep
, mnt_flags
[i
].m_name
);
flags
&= ~mnt_flags
[i
].m_flag
;
(void)printf("%sunknown_flags:%x", sep
, flags
);
struct e_vnode
*vnodebase
;
return (kinfo_vnodes(avnodes
));
if (sysctl(mib
, 2, NULL
, ©size
, NULL
, 0) == -1)
err(1, "sysctl: KERN_VNODE");
if ((vnodebase
= malloc(copysize
)) == NULL
)
if (sysctl(mib
, 2, vnodebase
, ©size
, NULL
, 0) == -1)
err(1, "sysctl: KERN_VNODE");
if (copysize
% sizeof(struct e_vnode
))
errx(1, "vnode size mismatch");
*avnodes
= copysize
/ sizeof(struct e_vnode
);
* simulate what a running kernel does in in kinfo_vnode
struct mntlist mountlist
;
#define VPTRSZ sizeof(struct vnode *)
#define VNODESZ sizeof(struct vnode)
if ((vbuf
= malloc((numvnodes
+ 20) * (VPTRSZ
+ VNODESZ
))) == NULL
)
evbuf
= vbuf
+ (numvnodes
+ 20) * (VPTRSZ
+ VNODESZ
);
KGET(V_MOUNTLIST
, mountlist
);
for (num
= 0, mp
= mountlist
.cqh_first
; ; mp
= mp
->mnt_list
.cqe_next
) {
KGET2(mp
, &mount
, sizeof(mount
), "mount entry");
for (vp
= mount
.mnt_vnodelist
.lh_first
;
vp
!= NULL
; vp
= vp
->v_mntvnodes
.le_next
) {
KGET2(vp
, &vnode
, sizeof(vnode
), "vnode");
if ((bp
+ VPTRSZ
+ VNODESZ
) > evbuf
)
/* XXX - should realloc */
errx(1, "no more room for vnodes");
memmove(bp
, &vp
, VPTRSZ
);
memmove(bp
, &vnode
, VNODESZ
);
if (mp
== mountlist
.cqh_last
)
return ((struct e_vnode
*)vbuf
);
char hdr
[]=" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n";
if ((tty
= malloc(ttyspace
* sizeof(*tty
))) == NULL
)
#if !defined(hp300) && !defined(mips)
(void)printf("1 console\n");
if (nl
[SNQD
].n_type
!= 0)
if (nl
[SNDZ
].n_type
!= 0)
ttytype(tty
, "dz", SDZ
, SNDZ
);
if (nl
[SNDH
].n_type
!= 0)
ttytype(tty
, "dh", SDH
, SNDH
);
if (nl
[SNDMF
].n_type
!= 0)
ttytype(tty
, "dmf", SDMF
, SNDMF
);
if (nl
[SNDHU
].n_type
!= 0)
ttytype(tty
, "dhu", SDHU
, SNDHU
);
if (nl
[SNDMZ
].n_type
!= 0)
ttytype(tty
, "dmz", SDMZ
, SNDMZ
);
if (nl
[SNVX
].n_type
!= 0)
ttytype(tty
, "vx", SVX
, SNVX
);
if (nl
[SNMP
].n_type
!= 0)
ttytype(tty
, "mp", SMP
, SNMP
);
if (nl
[SNITE
].n_type
!= 0)
ttytype(tty
, "ite", SITE
, SNITE
);
if (nl
[SNDCA
].n_type
!= 0)
ttytype(tty
, "dca", SDCA
, SNDCA
);
if (nl
[SNDCM
].n_type
!= 0)
ttytype(tty
, "dcm", SDCM
, SNDCM
);
if (nl
[SNDCL
].n_type
!= 0)
ttytype(tty
, "dcl", SDCL
, SNDCL
);
if (nl
[SNDC
].n_type
!= 0)
ttytype(tty
, "dc", SDC
, SNDC
);
if (nl
[SNPTY
].n_type
!= 0)
ttytype(tty
, "pty", SPTY
, SNPTY
);
ttytype(tty
, name
, type
, number
)
(void)printf("%d %s %s\n", ntty
, name
, (ntty
== 1) ? "line" : "lines");
if ((tty
= realloc(tty
, ttyspace
* sizeof(*tty
))) == 0)
KGET1(type
, tty
, ntty
* sizeof(struct tty
), "tty structs");
for (tp
= tty
; tp
< &tty
[ntty
]; tp
++)
if (usenumflag
|| tp
->t_dev
== 0 ||
(name
= devname(tp
->t_dev
, S_IFCHR
)) == NULL
)
(void)printf("%7d ", line
);
(void)printf("%7s ", name
);
(void)printf("%2d %3d ", tp
->t_rawq
.c_cc
, tp
->t_canq
.c_cc
);
(void)printf("%3d %4d %3d %7d ", tp
->t_outq
.c_cc
,
tp
->t_hiwat
, tp
->t_lowat
, tp
->t_column
);
for (i
= j
= 0; ttystates
[i
].flag
; i
++)
if (tp
->t_state
&ttystates
[i
].flag
)
state
[j
++] = ttystates
[i
].val
;
(void)printf("%-6s %8x", state
, (u_long
)tp
->t_session
);
KGET2(&tp
->t_pgrp
->pg_id
, &pgid
, sizeof(pid_t
), "pgid");
(void)printf("%6d ", pgid
);
(void)printf("%d\n", tp
->t_line
);
char *buf
, flagbuf
[16], *fbp
;
static char *dtypes
[] = { "???", "inode", "socket" };
KGET(FNL_MAXFILE
, maxfile
);
(void)printf("%3d/%3d files\n", nfile
, maxfile
);
if (getfiles(&buf
, &len
) == -1)
* Getfiles returns in malloc'd memory a pointer to the first file
* structure, and then an array of file structs (whose addresses are
* derivable from the previous entry).
addr
= ((struct filelist
*)buf
)->lh_first
;
fp
= (struct file
*)(buf
+ sizeof(struct filelist
));
nfile
= (len
- sizeof(struct filelist
)) / sizeof(struct file
);
(void)printf("%d/%d open files\n", nfile
, maxfile
);
(void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n");
for (; (char *)fp
< buf
+ len
; addr
= fp
->f_list
.le_next
, fp
++) {
if ((unsigned)fp
->f_type
> DTYPE_SOCKET
)
(void)printf("%x ", addr
);
(void)printf("%-8.8s", dtypes
[fp
->f_type
]);
if (fp
->f_flag
& FAPPEND
)
#ifdef FSHLOCK /* currently gone */
if (fp
->f_flag
& FSHLOCK
)
if (fp
->f_flag
& FEXLOCK
)
(void)printf("%6s %3d", flagbuf
, fp
->f_count
);
(void)printf(" %3d", fp
->f_msgcount
);
(void)printf(" %8.1x", fp
->f_data
);
(void)printf(" %qx\n", fp
->f_offset
);
(void)printf(" %qd\n", fp
->f_offset
);
* Add emulation of KINFO_FILE here.
errx(1, "files on dead kernel, not implemented\n");
if (sysctl(mib
, 2, NULL
, &len
, NULL
, 0) == -1) {
warn("sysctl: KERN_FILE");
if ((buf
= malloc(len
)) == NULL
)
if (sysctl(mib
, 2, buf
, &len
, NULL
, 0) == -1) {
warn("sysctl: KERN_FILE");
* swapmode is based on a program called swapinfo written
* by Kevin Lahey <kml@rokkaku.atl.ga.us>.
int hlen
, nswap
, nswdev
, dmmax
, nswapmap
, niswap
, niswdev
;
int s
, e
, div
, i
, l
, avail
, nfree
, npfree
, used
;
struct map
*swapmap
, *kswapmap
;
KGET(VM_NSWAPMAP
, nswapmap
);
KGET(VM_SWAPMAP
, kswapmap
); /* kernel `swapmap' is a pointer */
if ((sw
= malloc(nswdev
* sizeof(*sw
))) == NULL
||
(perdev
= malloc(nswdev
* sizeof(*perdev
))) == NULL
||
(mp
= malloc(nswapmap
* sizeof(*mp
))) == NULL
)
KGET1(VM_SWDEVT
, sw
, nswdev
* sizeof(*sw
), "swdevt");
KGET2((long)kswapmap
, mp
, nswapmap
* sizeof(*mp
), "swapmap");
/* Supports sequential swap */
if (nl
[VM_NISWAP
].n_value
!= 0) {
KGET(VM_NISWDEV
, niswdev
);
/* First entry in map is `struct map'; rest are mapent's. */
swapmap
= (struct map
*)mp
;
if (nswapmap
!= swapmap
->m_limit
- (struct mapent
*)kswapmap
)
errx(1, "panic: nswapmap goof");
/* Count up swap space. */
memset(perdev
, 0, nswdev
* sizeof(*perdev
));
for (mp
++; mp
->m_addr
!= 0; mp
++) {
s
= mp
->m_addr
; /* start of swap region */
e
= mp
->m_addr
+ mp
->m_size
; /* end of region */
* Swap space is split up among the configured disks.
* For interleaved swap devices, the first dmmax blocks
* of swap space some from the first disk, the next dmmax
* blocks from the next, and so on up to niswap blocks.
* Sequential swap devices follow the interleaved devices
* (i.e. blocks starting at niswap) in the order in which
* they appear in the swdev table. The size of each device
* will be a multiple of dmmax.
* The list of free space joins adjacent free blocks,
* ignoring device boundries. If we want to keep track
* of this information per device, we'll just have to
* extract it ourselves. We know that dmmax-sized chunks
* cannot span device boundaries (interleaved or sequential)
* so we loop over such chunks assigning them to devices.
while (s
< e
) { /* XXX this is inefficient */
int bound
= roundup(s
+1, dmmax
);
/* Interleaved swap chunk. */
i
= (s
/ dmmax
) % niswdev
;
/* Sequential swap chunk. */
l
= niswap
+ sw
[i
].sw_nblks
;
/* XXX don't die on bogus blocks */
header
= getbsize(&hlen
, &blocksize
);
(void)printf("%-11s %*s %8s %8s %8s %s\n",
"Used", "Avail", "Capacity", "Type");
for (i
= 0; i
< nswdev
; i
++) {
p
= devname(sw
[i
].sw_dev
, S_IFBLK
);
(void)printf("/dev/%-6s %*d ", p
== NULL
? "??" : p
,
hlen
, sw
[i
].sw_nblks
/ div
);
* Don't report statistics for partitions which have not
* yet been activated via swapon(8).
if (!(sw
[i
].sw_flags
& SW_FREED
)) {
(void)printf(" *** not available for swapping ***\n");
(void)printf("%8d %8d %5.0f%% %s\n",
(double)used
/ (double)xsize
* 100.0,
(sw
[i
].sw_flags
& SW_SEQUENTIAL
) ?
"Sequential" : "Interleaved");
* If only one partition has been set up via swapon(8), we don't
* need to bother with totals.
(void)printf("%dM/%dM swap space\n", used
/ 2048, avail
/ 2048);
(void)printf("%-11s %*d %8d %8d %5.0f%%\n",
"Total", hlen
, avail
/ div
, used
/ div
, nfree
/ div
,
(double)used
/ (double)avail
* 100.0);
"usage: pstat -Tfnstv [system] [-M core] [-N system]\n");