11553Srgrimes/*-
223687Speter * Copyright (c) 1980, 1991, 1993, 1994
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
497378Sdes * Copyright (c) 2002 Networks Associates Technologies, Inc.
597378Sdes * All rights reserved.
61553Srgrimes *
797378Sdes * Portions of this software were developed for the FreeBSD Project by
897378Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network
997378Sdes * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
1097378Sdes * ("CBOSS"), as part of the DARPA CHATS research program.
1197378Sdes *
121553Srgrimes * Redistribution and use in source and binary forms, with or without
131553Srgrimes * modification, are permitted provided that the following conditions
141553Srgrimes * are met:
151553Srgrimes * 1. Redistributions of source code must retain the above copyright
161553Srgrimes *    notice, this list of conditions and the following disclaimer.
171553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
181553Srgrimes *    notice, this list of conditions and the following disclaimer in the
191553Srgrimes *    documentation and/or other materials provided with the distribution.
201553Srgrimes * 4. Neither the name of the University nor the names of its contributors
211553Srgrimes *    may be used to endorse or promote products derived from this software
221553Srgrimes *    without specific prior written permission.
231553Srgrimes *
241553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341553Srgrimes * SUCH DAMAGE.
351553Srgrimes */
361553Srgrimes
37114601Sobrien#if 0
381553Srgrimes#ifndef lint
3930243Scharnierstatic const char copyright[] =
4023687Speter"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
411553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
421553Srgrimes#endif /* not lint */
431553Srgrimes
441553Srgrimes#ifndef lint
4523687Speterstatic char sccsid[] = "@(#)pstat.c	8.16 (Berkeley) 5/9/95";
46114601Sobrien#endif /* not lint */
4730243Scharnier#endif
48114601Sobrien#include <sys/cdefs.h>
49114601Sobrien__FBSDID("$FreeBSD$");
501553Srgrimes
511553Srgrimes#include <sys/param.h>
521553Srgrimes#include <sys/time.h>
531553Srgrimes#include <sys/file.h>
541553Srgrimes#include <sys/stat.h>
5597176Sdes#include <sys/stdint.h>
561553Srgrimes#include <sys/ioctl.h>
571553Srgrimes#include <sys/tty.h>
5842955Sdillon#include <sys/blist.h>
591553Srgrimes
601553Srgrimes#include <sys/sysctl.h>
61138129Sdas#include <vm/vm_param.h>
621553Srgrimes
631553Srgrimes#include <err.h>
64138129Sdas#include <errno.h>
6518570Sbde#include <fcntl.h>
661553Srgrimes#include <kvm.h>
67143929Skeramida#include <libutil.h>
681553Srgrimes#include <limits.h>
691553Srgrimes#include <nlist.h>
701553Srgrimes#include <stdio.h>
711553Srgrimes#include <stdlib.h>
721553Srgrimes#include <string.h>
731553Srgrimes#include <unistd.h>
741553Srgrimes
7597375Sdesenum {
7697375Sdes	NL_CONSTTY,
7797375Sdes	NL_MAXFILES,
7897375Sdes	NL_NFILES,
79194014Sstas	NL_TTY_LIST,
80194014Sstas	NL_MARKER
8197375Sdes};
8297375Sdes
83194014Sstasstatic struct {
84194014Sstas	int order;
85194014Sstas	const char *name;
86194014Sstas} namelist[] = {
87194014Sstas	{ NL_CONSTTY, "_constty" },
88194014Sstas	{ NL_MAXFILES, "_maxfiles" },
89194014Sstas	{ NL_NFILES, "_openfiles" },
90194014Sstas	{ NL_TTY_LIST, "_tty_list" },
91194014Sstas	{ NL_MARKER, "" },
921553Srgrimes};
93194014Sstas#define NNAMES	(sizeof(namelist) / sizeof(*namelist))
94194014Sstasstatic struct nlist nl[NNAMES];
951553Srgrimes
96143929Skeramidastatic int	humanflag;
9797171Sdesstatic int	usenumflag;
9897171Sdesstatic int	totalflag;
9997171Sdesstatic int	swapflag;
10097174Sdesstatic char	*nlistf;
10197174Sdesstatic char	*memf;
10297171Sdesstatic kvm_t	*kd;
1031553Srgrimes
104193978Sedstatic const char *usagestr;
1058495Sphk
10697172Sdesstatic void	filemode(void);
107194014Sstasstatic int	getfiles(struct xfile **, size_t *);
10897172Sdesstatic void	swapmode(void);
10997172Sdesstatic void	ttymode(void);
11097367Sdesstatic void	ttyprt(struct xtty *);
11197172Sdesstatic void	usage(void);
1121553Srgrimes
1131553Srgrimesint
11497172Sdesmain(int argc, char *argv[])
1151553Srgrimes{
116194014Sstas	int ch, quit, ret;
11797173Sdes	int fileflag, ttyflag;
118194014Sstas	unsigned int i;
119193978Sed	char buf[_POSIX2_LINE_MAX];
120193978Sed	const char *opts;
1211553Srgrimes
12297173Sdes	fileflag = swapflag = ttyflag = 0;
1238495Sphk
1248495Sphk	/* We will behave like good old swapinfo if thus invoked */
12597378Sdes	opts = strrchr(argv[0], '/');
1268495Sphk	if (opts)
1278495Sphk		opts++;
1288495Sphk	else
1298495Sphk		opts = argv[0];
13097378Sdes	if (!strcmp(opts, "swapinfo")) {
1318495Sphk		swapflag = 1;
132168227Smarkm		opts = "ghkmM:N:";
133168227Smarkm		usagestr = "swapinfo [-ghkm] [-M core [-N system]]";
1348495Sphk	} else {
135168292Sru		opts = "TM:N:fghkmnst";
136168292Sru		usagestr = "pstat [-Tfghkmnst] [-M core [-N system]]";
1378495Sphk	}
1388495Sphk
13924428Simp	while ((ch = getopt(argc, argv, opts)) != -1)
1401553Srgrimes		switch (ch) {
1411553Srgrimes		case 'f':
1421553Srgrimes			fileflag = 1;
1431553Srgrimes			break;
144168227Smarkm		case 'g':
145171195Sscf			setenv("BLOCKSIZE", "1G", 1);
146168227Smarkm			break;
147143929Skeramida		case 'h':
148143929Skeramida			humanflag = 1;
149143929Skeramida			break;
1508495Sphk		case 'k':
151171195Sscf			setenv("BLOCKSIZE", "1K", 1);
1528495Sphk			break;
153168227Smarkm		case 'm':
154171195Sscf			setenv("BLOCKSIZE", "1M", 1);
155168227Smarkm			break;
1561553Srgrimes		case 'M':
1571553Srgrimes			memf = optarg;
1581553Srgrimes			break;
1591553Srgrimes		case 'N':
1601553Srgrimes			nlistf = optarg;
1611553Srgrimes			break;
1621553Srgrimes		case 'n':
1631553Srgrimes			usenumflag = 1;
1641553Srgrimes			break;
1651553Srgrimes		case 's':
16642955Sdillon			++swapflag;
1671553Srgrimes			break;
1681553Srgrimes		case 'T':
1691553Srgrimes			totalflag = 1;
1701553Srgrimes			break;
1711553Srgrimes		case 't':
1721553Srgrimes			ttyflag = 1;
1731553Srgrimes			break;
1741553Srgrimes		default:
17530243Scharnier			usage();
1761553Srgrimes		}
1771553Srgrimes	argc -= optind;
1781553Srgrimes	argv += optind;
1791553Srgrimes
180194014Sstas	/*
181194014Sstas	 * Initialize symbol names list.
182194014Sstas	 */
183194014Sstas	for (i = 0; i < NNAMES; i++)
184194014Sstas		nl[namelist[i].order].n_name = strdup(namelist[i].name);
185194014Sstas
18697176Sdes	if (memf != NULL) {
18797176Sdes		kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
18897176Sdes		if (kd == NULL)
18997176Sdes			errx(1, "kvm_openfiles: %s", buf);
19097176Sdes		if ((ret = kvm_nlist(kd, nl)) != 0) {
19197176Sdes			if (ret == -1)
19297176Sdes				errx(1, "kvm_nlist: %s", kvm_geterr(kd));
19397176Sdes			quit = 0;
19497375Sdes			for (i = 0; nl[i].n_name[0] != '\0'; ++i)
19597375Sdes				if (nl[i].n_value == 0) {
19697176Sdes					quit = 1;
19797176Sdes					warnx("undefined symbol: %s",
19897176Sdes					    nl[i].n_name);
19997176Sdes				}
20097176Sdes			if (quit)
20197176Sdes				exit(1);
20297176Sdes		}
2031553Srgrimes	}
20497173Sdes	if (!(fileflag | ttyflag | swapflag | totalflag))
20530243Scharnier		usage();
2061553Srgrimes	if (fileflag || totalflag)
2071553Srgrimes		filemode();
2081553Srgrimes	if (ttyflag)
2091553Srgrimes		ttymode();
2101553Srgrimes	if (swapflag || totalflag)
2111553Srgrimes		swapmode();
2121553Srgrimes	exit (0);
2131553Srgrimes}
2141553Srgrimes
21530243Scharnierstatic void
21697172Sdesusage(void)
21730243Scharnier{
21830243Scharnier	fprintf(stderr, "usage: %s\n", usagestr);
21930243Scharnier	exit (1);
22030243Scharnier}
22130243Scharnier
222110148Srobertstatic const char fhdr32[] =
223110148Srobert  "   LOC   TYPE   FLG  CNT MSG   DATA        OFFSET\n";
224110148Srobert/* c0000000 ------ RWAI 123 123 c0000000 1000000000000000 */
225110148Srobert
226110148Srobertstatic const char fhdr64[] =
227110148Srobert  "       LOC       TYPE   FLG  CNT MSG       DATA            OFFSET\n";
228110148Srobert/* c000000000000000 ------ RWAI 123 123 c000000000000000 1000000000000000 */
229110148Srobert
23097171Sdesstatic const char hdr[] =
231181905Sed"      LINE   INQ  CAN  LIN  LOW  OUTQ  USE  LOW   COL  SESS  PGID STATE\n";
2321553Srgrimes
23397171Sdesstatic void
23497375Sdesttymode_kvm(void)
2351553Srgrimes{
236130267Sphk	TAILQ_HEAD(, tty) tl;
23797375Sdes	struct tty *tp, tty;
23897375Sdes	struct xtty xt;
23997375Sdes
24097375Sdes	(void)printf("%s", hdr);
24197375Sdes	bzero(&xt, sizeof xt);
24297375Sdes	xt.xt_size = sizeof xt;
24397375Sdes	if (kvm_read(kd, nl[NL_TTY_LIST].n_value, &tl, sizeof tl) != sizeof tl)
24497375Sdes		errx(1, "kvm_read(): %s", kvm_geterr(kd));
245130267Sphk	tp = TAILQ_FIRST(&tl);
24697375Sdes	while (tp != NULL) {
24797375Sdes		if (kvm_read(kd, (u_long)tp, &tty, sizeof tty) != sizeof tty)
24897375Sdes			errx(1, "kvm_read(): %s", kvm_geterr(kd));
249181905Sed		xt.xt_insize = tty.t_inq.ti_nblocks * TTYINQ_DATASIZE;
250181905Sed		xt.xt_incc = tty.t_inq.ti_linestart - tty.t_inq.ti_begin;
251181905Sed		xt.xt_inlc = tty.t_inq.ti_end - tty.t_inq.ti_linestart;
252181905Sed		xt.xt_inlow = tty.t_inlow;
253181905Sed		xt.xt_outsize = tty.t_outq.to_nblocks * TTYOUTQ_DATASIZE;
254181905Sed		xt.xt_outcc = tty.t_outq.to_end - tty.t_outq.to_begin;
255181905Sed		xt.xt_outlow = tty.t_outlow;
256181905Sed		xt.xt_column = tty.t_column;
257181905Sed		/* xt.xt_pgid = ... */
258181905Sed		/* xt.xt_sid = ... */
259181905Sed		xt.xt_flags = tty.t_flags;
260181905Sed		xt.xt_dev = NODEV;
26197375Sdes		ttyprt(&xt);
262178987Sremko		tp = TAILQ_NEXT(&tty, t_list);
26397375Sdes	}
26497375Sdes}
26597375Sdes
26697375Sdesstatic void
26797375Sdesttymode_sysctl(void)
26897375Sdes{
269194014Sstas	struct xtty *xttys;
27097367Sdes	size_t len;
271194014Sstas	unsigned int i, n;
2721553Srgrimes
27378378Sdd	(void)printf("%s", hdr);
274194014Sstas	if ((xttys = malloc(len = sizeof(*xttys))) == NULL)
27597367Sdes		err(1, "malloc()");
27697367Sdes	while (sysctlbyname("kern.ttys", xttys, &len, 0, 0) == -1) {
27797367Sdes		if (errno != ENOMEM)
27897367Sdes			err(1, "sysctlbyname()");
27997367Sdes		len *= 2;
28097367Sdes		if ((xttys = realloc(xttys, len)) == NULL)
28197367Sdes			err(1, "realloc()");
28249539Sphk	}
283194014Sstas	n = len / sizeof(*xttys);
284194014Sstas	for (i = 0; i < n; i++)
285194014Sstas		ttyprt(&xttys[i]);
2861553Srgrimes}
2871553Srgrimes
28897171Sdesstatic void
28997375Sdesttymode(void)
2901553Srgrimes{
2911553Srgrimes
29297375Sdes	if (kd != NULL)
29397375Sdes		ttymode_kvm();
29497375Sdes	else
29597375Sdes		ttymode_sysctl();
2961553Srgrimes}
2971553Srgrimes
29897171Sdesstatic struct {
2991553Srgrimes	int flag;
3001553Srgrimes	char val;
3011553Srgrimes} ttystates[] = {
302181905Sed#if 0
303188147Sed	{ TF_NOPREFIX,		'N' },
3049620Sbde#endif
305188147Sed	{ TF_INITLOCK,		'I' },
306188147Sed	{ TF_CALLOUT,		'C' },
307181905Sed
308181905Sed	/* Keep these together -> 'Oi' and 'Oo'. */
309188147Sed	{ TF_OPENED,		'O' },
310188147Sed	{ TF_OPENED_IN,		'i' },
311188147Sed	{ TF_OPENED_OUT,	'o' },
312188147Sed	{ TF_OPENED_CONS,	'c' },
313181905Sed
314188147Sed	{ TF_GONE,		'G' },
315188147Sed	{ TF_OPENCLOSE,		'B' },
316188147Sed	{ TF_ASYNC,		'Y' },
317188147Sed	{ TF_LITERAL,		'L' },
318181905Sed
319181905Sed	/* Keep these together -> 'Hi' and 'Ho'. */
320188147Sed	{ TF_HIWAT,		'H' },
321188147Sed	{ TF_HIWAT_IN,		'i' },
322188147Sed	{ TF_HIWAT_OUT,		'o' },
323181905Sed
324188147Sed	{ TF_STOPPED,		'S' },
325188147Sed	{ TF_EXCLUDE,		'X' },
326188147Sed	{ TF_BYPASS,		'l' },
327188147Sed	{ TF_ZOMBIE,		'Z' },
328188147Sed	{ TF_HOOK,		's' },
329181905Sed
330188487Sed	/* Keep these together -> 'bi' and 'bo'. */
331188487Sed	{ TF_BUSY,		'b' },
332188487Sed	{ TF_BUSY_IN,		'i' },
333188487Sed	{ TF_BUSY_OUT,		'o' },
334188487Sed
335188147Sed	{ 0,			'\0'},
3361553Srgrimes};
3371553Srgrimes
33897171Sdesstatic void
33997367Sdesttyprt(struct xtty *xt)
3401553Srgrimes{
34123687Speter	int i, j;
342181905Sed	char *name;
3431553Srgrimes
34497367Sdes	if (xt->xt_size != sizeof *xt)
34597367Sdes		errx(1, "struct xtty size mismatch");
34697367Sdes	if (usenumflag || xt->xt_dev == 0 ||
34797367Sdes	   (name = devname(xt->xt_dev, S_IFCHR)) == NULL)
348181905Sed		printf("%5d,%4d ", major(xt->xt_dev), minor(xt->xt_dev));
3491553Srgrimes	else
350181905Sed		printf("%10s ", name);
351181905Sed	printf("%5zu %4zu %4zu %4zu %5zu %4zu %4zu %5u %5d %5d ",
352181905Sed	    xt->xt_insize, xt->xt_incc, xt->xt_inlc,
353181905Sed	    (xt->xt_insize - xt->xt_inlow), xt->xt_outsize,
354181905Sed	    xt->xt_outcc, (xt->xt_outsize - xt->xt_outlow),
355184522Sed	    MIN(xt->xt_column, 99999), xt->xt_sid, xt->xt_pgid);
3561553Srgrimes	for (i = j = 0; ttystates[i].flag; i++)
357181905Sed		if (xt->xt_flags & ttystates[i].flag) {
358181905Sed			putchar(ttystates[i].val);
359181905Sed			j++;
360181905Sed		}
3611553Srgrimes	if (j == 0)
362181905Sed		putchar('-');
363181905Sed	putchar('\n');
3641553Srgrimes}
3651553Srgrimes
36697171Sdesstatic void
36797172Sdesfilemode(void)
3681553Srgrimes{
369194014Sstas	struct xfile *fp, *buf;
370194014Sstas	char flagbuf[16], *fbp;
37197378Sdes	int maxf, openf;
37297176Sdes	size_t len;
373193982Sed	static char const * const dtypes[] = { "???", "inode", "socket",
374193978Sed	    "pipe", "fifo", "kqueue", "crypto" };
375101044Sdes	int i;
376110148Srobert	int wid;
3771553Srgrimes
37897176Sdes	if (kd != NULL) {
37997378Sdes		if (kvm_read(kd, nl[NL_MAXFILES].n_value,
38097378Sdes			&maxf, sizeof maxf) != sizeof maxf ||
38197378Sdes		    kvm_read(kd, nl[NL_NFILES].n_value,
38297378Sdes			&openf, sizeof openf) != sizeof openf)
38397378Sdes			errx(1, "kvm_read(): %s", kvm_geterr(kd));
38497176Sdes	} else {
38597378Sdes		len = sizeof(int);
38697378Sdes		if (sysctlbyname("kern.maxfiles", &maxf, &len, 0, 0) == -1 ||
38797378Sdes		    sysctlbyname("kern.openfiles", &openf, &len, 0, 0) == -1)
38897176Sdes			err(1, "sysctlbyname()");
38997176Sdes	}
39097176Sdes
3911553Srgrimes	if (totalflag) {
39297378Sdes		(void)printf("%3d/%3d files\n", openf, maxf);
3931553Srgrimes		return;
3941553Srgrimes	}
3951553Srgrimes	if (getfiles(&buf, &len) == -1)
3961553Srgrimes		return;
397101044Sdes	openf = len / sizeof *fp;
398110148Srobert
39997378Sdes	(void)printf("%d/%d open files\n", openf, maxf);
400110148Srobert	printf(sizeof(uintptr_t) == 4 ? fhdr32 : fhdr64);
401110148Srobert	wid = (int)sizeof(uintptr_t) * 2;
402101044Sdes	for (fp = (struct xfile *)buf, i = 0; i < openf; ++fp, ++i) {
403110148Srobert		if ((size_t)fp->xf_type >= sizeof(dtypes) / sizeof(dtypes[0]))
4041553Srgrimes			continue;
405110148Srobert		(void)printf("%*jx", wid, (uintmax_t)(uintptr_t)fp->xf_file);
406110148Srobert		(void)printf(" %-6.6s", dtypes[fp->xf_type]);
4071553Srgrimes		fbp = flagbuf;
408101044Sdes		if (fp->xf_flag & FREAD)
4091553Srgrimes			*fbp++ = 'R';
410101044Sdes		if (fp->xf_flag & FWRITE)
4111553Srgrimes			*fbp++ = 'W';
412101044Sdes		if (fp->xf_flag & FAPPEND)
4131553Srgrimes			*fbp++ = 'A';
414101044Sdes		if (fp->xf_flag & FASYNC)
4151553Srgrimes			*fbp++ = 'I';
4161553Srgrimes		*fbp = '\0';
417110148Srobert		(void)printf(" %4s %3d", flagbuf, fp->xf_count);
418110148Srobert		(void)printf(" %3d", fp->xf_msgcount);
419110148Srobert		(void)printf(" %*jx", wid, (uintmax_t)(uintptr_t)fp->xf_data);
420110148Srobert		(void)printf(" %*jx\n", (int)sizeof(fp->xf_offset) * 2,
421110148Srobert		    (uintmax_t)fp->xf_offset);
4221553Srgrimes	}
4231553Srgrimes	free(buf);
4241553Srgrimes}
4251553Srgrimes
42697171Sdesstatic int
427194014Sstasgetfiles(struct xfile **abuf, size_t *alen)
4281553Srgrimes{
429194014Sstas	struct xfile *buf;
4301553Srgrimes	size_t len;
4311553Srgrimes	int mib[2];
4321553Srgrimes
4331553Srgrimes	/*
4341553Srgrimes	 * XXX
4351553Srgrimes	 * Add emulation of KINFO_FILE here.
4361553Srgrimes	 */
43797176Sdes	if (kd != NULL)
43830243Scharnier		errx(1, "files on dead kernel, not implemented");
4391553Srgrimes
4401553Srgrimes	mib[0] = CTL_KERN;
4411553Srgrimes	mib[1] = KERN_FILE;
4421553Srgrimes	if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
4431553Srgrimes		warn("sysctl: KERN_FILE");
4441553Srgrimes		return (-1);
4451553Srgrimes	}
4461553Srgrimes	if ((buf = malloc(len)) == NULL)
44730243Scharnier		errx(1, "malloc");
4481553Srgrimes	if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
4491553Srgrimes		warn("sysctl: KERN_FILE");
4501553Srgrimes		return (-1);
4511553Srgrimes	}
4521553Srgrimes	*abuf = buf;
4531553Srgrimes	*alen = len;
4541553Srgrimes	return (0);
4551553Srgrimes}
4561553Srgrimes
4571553Srgrimes/*
4581553Srgrimes * swapmode is based on a program called swapinfo written
4591553Srgrimes * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
4601553Srgrimes */
46197176Sdes
462143929Skeramida#define CONVERT(v)	((int64_t)(v) * pagesize / blocksize)
463196244Sstas#define CONVERT_BLOCKS(v)	((int64_t)(v) * pagesize)
46497176Sdesstatic struct kvm_swap swtot;
46597176Sdesstatic int nswdev;
46697176Sdes
46797171Sdesstatic void
46897176Sdesprint_swap_header(void)
4691553Srgrimes{
470108457Smike	int hlen;
47143046Sdillon	long blocksize;
47297176Sdes	const char *header;
4731553Srgrimes
4741553Srgrimes	header = getbsize(&hlen, &blocksize);
47597176Sdes	if (totalflag == 0)
476118275Sphk		(void)printf("%-15s %*s %8s %8s %8s\n",
477108457Smike		    "Device", hlen, header,
478118275Sphk		    "Used", "Avail", "Capacity");
47997176Sdes}
48042955Sdillon
48197176Sdesstatic void
482193978Sedprint_swap_line(const char *swdevname, intmax_t nblks, intmax_t bused,
483143929Skeramida    intmax_t bavail, float bpercent)
48497176Sdes{
485143929Skeramida	char usedbuf[5];
486143929Skeramida	char availbuf[5];
487108457Smike	int hlen, pagesize;
48897176Sdes	long blocksize;
48997176Sdes
49097176Sdes	pagesize = getpagesize();
49197176Sdes	getbsize(&hlen, &blocksize);
492143929Skeramida
493193978Sed	printf("%-15s %*jd ", swdevname, hlen, CONVERT(nblks));
494143929Skeramida	if (humanflag) {
495143929Skeramida		humanize_number(usedbuf, sizeof(usedbuf),
496196244Sstas		    CONVERT_BLOCKS(bused), "",
497143929Skeramida		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
498143929Skeramida		humanize_number(availbuf, sizeof(availbuf),
499196244Sstas		    CONVERT_BLOCKS(bavail), "",
500143929Skeramida		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
501143929Skeramida		printf("%8s %8s %5.0f%%\n", usedbuf, availbuf, bpercent);
502143929Skeramida	} else {
503143929Skeramida		printf("%8jd %8jd %5.0f%%\n", (intmax_t)CONVERT(bused),
504143929Skeramida		    (intmax_t)CONVERT(bavail), bpercent);
505143929Skeramida	}
506143929Skeramida}
507143929Skeramida
508143929Skeramidastatic void
509143929Skeramidaprint_swap(struct kvm_swap *ksw)
510143929Skeramida{
511143929Skeramida
51297176Sdes	swtot.ksw_total += ksw->ksw_total;
51397176Sdes	swtot.ksw_used += ksw->ksw_used;
51497176Sdes	++nswdev;
515143929Skeramida	if (totalflag == 0)
516143929Skeramida		print_swap_line(ksw->ksw_devname, ksw->ksw_total,
517152558Srwatson		    ksw->ksw_used, ksw->ksw_total - ksw->ksw_used,
518118275Sphk		    (ksw->ksw_used * 100.0) / ksw->ksw_total);
51997176Sdes}
52042955Sdillon
52197176Sdesstatic void
52297176Sdesprint_swap_total(void)
52397176Sdes{
524108457Smike	int hlen, pagesize;
52597176Sdes	long blocksize;
52697176Sdes
52797176Sdes	pagesize = getpagesize();
52897176Sdes	getbsize(&hlen, &blocksize);
52943046Sdillon	if (totalflag) {
53043046Sdillon		blocksize = 1024 * 1024;
531143929Skeramida		(void)printf("%jdM/%jdM swap space\n",
53297176Sdes		    CONVERT(swtot.ksw_used), CONVERT(swtot.ksw_total));
53397176Sdes	} else if (nswdev > 1) {
534143929Skeramida		print_swap_line("Total", swtot.ksw_total, swtot.ksw_used,
535143929Skeramida		    swtot.ksw_total - swtot.ksw_used,
53697176Sdes		    (swtot.ksw_used * 100.0) / swtot.ksw_total);
53797176Sdes	}
53897176Sdes}
5391553Srgrimes
54097176Sdesstatic void
54197176Sdesswapmode_kvm(void)
54297176Sdes{
54397176Sdes	struct kvm_swap kswap[16];
54497176Sdes	int i, n;
54597176Sdes
54697176Sdes	n = kvm_getswapinfo(kd, kswap, sizeof kswap / sizeof kswap[0],
547118278Sphk	    SWIF_DEV_PREFIX);
54897176Sdes
54997176Sdes	print_swap_header();
55097176Sdes	for (i = 0; i < n; ++i)
55197176Sdes		print_swap(&kswap[i]);
55297176Sdes	print_swap_total();
55397176Sdes}
55497176Sdes
55597176Sdesstatic void
55697176Sdesswapmode_sysctl(void)
55797176Sdes{
55897176Sdes	struct kvm_swap ksw;
55997176Sdes	struct xswdev xsw;
56097176Sdes	size_t mibsize, size;
56197176Sdes	int mib[16], n;
56297176Sdes
56397176Sdes	print_swap_header();
56497176Sdes	mibsize = sizeof mib / sizeof mib[0];
56597176Sdes	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
56697176Sdes		err(1, "sysctlnametomib()");
56797176Sdes	for (n = 0; ; ++n) {
56897176Sdes		mib[mibsize] = n;
56997176Sdes		size = sizeof xsw;
570126643Smarkm		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
57197176Sdes			break;
57297176Sdes		if (xsw.xsw_version != XSWDEV_VERSION)
57397176Sdes			errx(1, "xswdev version mismatch");
574115882Sphk		if (xsw.xsw_dev == NODEV)
575115882Sphk			snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
576115882Sphk			    "<NFSfile>");
577115882Sphk		else
578115882Sphk			snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
579115882Sphk			    "/dev/%s", devname(xsw.xsw_dev, S_IFCHR));
58097176Sdes		ksw.ksw_used = xsw.xsw_used;
58197176Sdes		ksw.ksw_total = xsw.xsw_nblks;
58297176Sdes		ksw.ksw_flags = xsw.xsw_flags;
58397176Sdes		print_swap(&ksw);
5841553Srgrimes	}
58597176Sdes	if (errno != ENOENT)
58697176Sdes		err(1, "sysctl()");
58797176Sdes	print_swap_total();
5881553Srgrimes}
58997176Sdes
59097176Sdesstatic void
59197176Sdesswapmode(void)
59297176Sdes{
59397176Sdes	if (kd != NULL)
59497176Sdes		swapmode_kvm();
59597176Sdes	else
59697176Sdes		swapmode_sysctl();
59797176Sdes}
598