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: stable/10/usr.sbin/pstat/pstat.c 311753 2017-01-09 05:58:48Z delphij $");
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
178194014Sstas	/*
179194014Sstas	 * Initialize symbol names list.
180194014Sstas	 */
181194014Sstas	for (i = 0; i < NNAMES; i++)
182194014Sstas		nl[namelist[i].order].n_name = strdup(namelist[i].name);
183194014Sstas
18497176Sdes	if (memf != NULL) {
18597176Sdes		kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
18697176Sdes		if (kd == NULL)
18797176Sdes			errx(1, "kvm_openfiles: %s", buf);
18897176Sdes		if ((ret = kvm_nlist(kd, nl)) != 0) {
18997176Sdes			if (ret == -1)
19097176Sdes				errx(1, "kvm_nlist: %s", kvm_geterr(kd));
19197176Sdes			quit = 0;
19297375Sdes			for (i = 0; nl[i].n_name[0] != '\0'; ++i)
19397375Sdes				if (nl[i].n_value == 0) {
19497176Sdes					quit = 1;
19597176Sdes					warnx("undefined symbol: %s",
19697176Sdes					    nl[i].n_name);
19797176Sdes				}
19897176Sdes			if (quit)
19997176Sdes				exit(1);
20097176Sdes		}
2011553Srgrimes	}
20297173Sdes	if (!(fileflag | ttyflag | swapflag | totalflag))
20330243Scharnier		usage();
2041553Srgrimes	if (fileflag || totalflag)
2051553Srgrimes		filemode();
2061553Srgrimes	if (ttyflag)
2071553Srgrimes		ttymode();
2081553Srgrimes	if (swapflag || totalflag)
2091553Srgrimes		swapmode();
2101553Srgrimes	exit (0);
2111553Srgrimes}
2121553Srgrimes
21330243Scharnierstatic void
21497172Sdesusage(void)
21530243Scharnier{
21630243Scharnier	fprintf(stderr, "usage: %s\n", usagestr);
21730243Scharnier	exit (1);
21830243Scharnier}
21930243Scharnier
220110148Srobertstatic const char fhdr32[] =
221110148Srobert  "   LOC   TYPE   FLG  CNT MSG   DATA        OFFSET\n";
222110148Srobert/* c0000000 ------ RWAI 123 123 c0000000 1000000000000000 */
223110148Srobert
224110148Srobertstatic const char fhdr64[] =
225110148Srobert  "       LOC       TYPE   FLG  CNT MSG       DATA            OFFSET\n";
226110148Srobert/* c000000000000000 ------ RWAI 123 123 c000000000000000 1000000000000000 */
227110148Srobert
22897171Sdesstatic const char hdr[] =
229181905Sed"      LINE   INQ  CAN  LIN  LOW  OUTQ  USE  LOW   COL  SESS  PGID STATE\n";
2301553Srgrimes
23197171Sdesstatic void
23297375Sdesttymode_kvm(void)
2331553Srgrimes{
234130267Sphk	TAILQ_HEAD(, tty) tl;
23597375Sdes	struct tty *tp, tty;
23697375Sdes	struct xtty xt;
23797375Sdes
23897375Sdes	(void)printf("%s", hdr);
23997375Sdes	bzero(&xt, sizeof xt);
24097375Sdes	xt.xt_size = sizeof xt;
24197375Sdes	if (kvm_read(kd, nl[NL_TTY_LIST].n_value, &tl, sizeof tl) != sizeof tl)
24297375Sdes		errx(1, "kvm_read(): %s", kvm_geterr(kd));
243130267Sphk	tp = TAILQ_FIRST(&tl);
24497375Sdes	while (tp != NULL) {
24597375Sdes		if (kvm_read(kd, (u_long)tp, &tty, sizeof tty) != sizeof tty)
24697375Sdes			errx(1, "kvm_read(): %s", kvm_geterr(kd));
247181905Sed		xt.xt_insize = tty.t_inq.ti_nblocks * TTYINQ_DATASIZE;
248181905Sed		xt.xt_incc = tty.t_inq.ti_linestart - tty.t_inq.ti_begin;
249181905Sed		xt.xt_inlc = tty.t_inq.ti_end - tty.t_inq.ti_linestart;
250181905Sed		xt.xt_inlow = tty.t_inlow;
251181905Sed		xt.xt_outsize = tty.t_outq.to_nblocks * TTYOUTQ_DATASIZE;
252181905Sed		xt.xt_outcc = tty.t_outq.to_end - tty.t_outq.to_begin;
253181905Sed		xt.xt_outlow = tty.t_outlow;
254181905Sed		xt.xt_column = tty.t_column;
255181905Sed		/* xt.xt_pgid = ... */
256181905Sed		/* xt.xt_sid = ... */
257181905Sed		xt.xt_flags = tty.t_flags;
258181905Sed		xt.xt_dev = NODEV;
25997375Sdes		ttyprt(&xt);
260178987Sremko		tp = TAILQ_NEXT(&tty, t_list);
26197375Sdes	}
26297375Sdes}
26397375Sdes
26497375Sdesstatic void
26597375Sdesttymode_sysctl(void)
26697375Sdes{
267194014Sstas	struct xtty *xttys;
26897367Sdes	size_t len;
269194014Sstas	unsigned int i, n;
2701553Srgrimes
27178378Sdd	(void)printf("%s", hdr);
272194014Sstas	if ((xttys = malloc(len = sizeof(*xttys))) == NULL)
27397367Sdes		err(1, "malloc()");
27497367Sdes	while (sysctlbyname("kern.ttys", xttys, &len, 0, 0) == -1) {
27597367Sdes		if (errno != ENOMEM)
27697367Sdes			err(1, "sysctlbyname()");
27797367Sdes		len *= 2;
27897367Sdes		if ((xttys = realloc(xttys, len)) == NULL)
27997367Sdes			err(1, "realloc()");
28049539Sphk	}
281194014Sstas	n = len / sizeof(*xttys);
282194014Sstas	for (i = 0; i < n; i++)
283194014Sstas		ttyprt(&xttys[i]);
2841553Srgrimes}
2851553Srgrimes
28697171Sdesstatic void
28797375Sdesttymode(void)
2881553Srgrimes{
2891553Srgrimes
29097375Sdes	if (kd != NULL)
29197375Sdes		ttymode_kvm();
29297375Sdes	else
29397375Sdes		ttymode_sysctl();
2941553Srgrimes}
2951553Srgrimes
29697171Sdesstatic struct {
2971553Srgrimes	int flag;
2981553Srgrimes	char val;
2991553Srgrimes} ttystates[] = {
300181905Sed#if 0
301188147Sed	{ TF_NOPREFIX,		'N' },
3029620Sbde#endif
303188147Sed	{ TF_INITLOCK,		'I' },
304188147Sed	{ TF_CALLOUT,		'C' },
305181905Sed
306181905Sed	/* Keep these together -> 'Oi' and 'Oo'. */
307188147Sed	{ TF_OPENED,		'O' },
308188147Sed	{ TF_OPENED_IN,		'i' },
309188147Sed	{ TF_OPENED_OUT,	'o' },
310188147Sed	{ TF_OPENED_CONS,	'c' },
311181905Sed
312188147Sed	{ TF_GONE,		'G' },
313188147Sed	{ TF_OPENCLOSE,		'B' },
314188147Sed	{ TF_ASYNC,		'Y' },
315188147Sed	{ TF_LITERAL,		'L' },
316181905Sed
317181905Sed	/* Keep these together -> 'Hi' and 'Ho'. */
318188147Sed	{ TF_HIWAT,		'H' },
319188147Sed	{ TF_HIWAT_IN,		'i' },
320188147Sed	{ TF_HIWAT_OUT,		'o' },
321181905Sed
322188147Sed	{ TF_STOPPED,		'S' },
323188147Sed	{ TF_EXCLUDE,		'X' },
324188147Sed	{ TF_BYPASS,		'l' },
325188147Sed	{ TF_ZOMBIE,		'Z' },
326188147Sed	{ TF_HOOK,		's' },
327181905Sed
328188487Sed	/* Keep these together -> 'bi' and 'bo'. */
329188487Sed	{ TF_BUSY,		'b' },
330188487Sed	{ TF_BUSY_IN,		'i' },
331188487Sed	{ TF_BUSY_OUT,		'o' },
332188487Sed
333188147Sed	{ 0,			'\0'},
3341553Srgrimes};
3351553Srgrimes
33697171Sdesstatic void
33797367Sdesttyprt(struct xtty *xt)
3381553Srgrimes{
33923687Speter	int i, j;
340311753Sdelphij	const char *name;
3411553Srgrimes
34297367Sdes	if (xt->xt_size != sizeof *xt)
34397367Sdes		errx(1, "struct xtty size mismatch");
34497367Sdes	if (usenumflag || xt->xt_dev == 0 ||
34597367Sdes	   (name = devname(xt->xt_dev, S_IFCHR)) == NULL)
346225847Sed		printf("%#10jx ", (uintmax_t)xt->xt_dev);
3471553Srgrimes	else
348181905Sed		printf("%10s ", name);
349181905Sed	printf("%5zu %4zu %4zu %4zu %5zu %4zu %4zu %5u %5d %5d ",
350181905Sed	    xt->xt_insize, xt->xt_incc, xt->xt_inlc,
351181905Sed	    (xt->xt_insize - xt->xt_inlow), xt->xt_outsize,
352181905Sed	    xt->xt_outcc, (xt->xt_outsize - xt->xt_outlow),
353184522Sed	    MIN(xt->xt_column, 99999), xt->xt_sid, xt->xt_pgid);
3541553Srgrimes	for (i = j = 0; ttystates[i].flag; i++)
355181905Sed		if (xt->xt_flags & ttystates[i].flag) {
356181905Sed			putchar(ttystates[i].val);
357181905Sed			j++;
358181905Sed		}
3591553Srgrimes	if (j == 0)
360181905Sed		putchar('-');
361181905Sed	putchar('\n');
3621553Srgrimes}
3631553Srgrimes
36497171Sdesstatic void
36597172Sdesfilemode(void)
3661553Srgrimes{
367194014Sstas	struct xfile *fp, *buf;
368194014Sstas	char flagbuf[16], *fbp;
36997378Sdes	int maxf, openf;
37097176Sdes	size_t len;
371193982Sed	static char const * const dtypes[] = { "???", "inode", "socket",
372193978Sed	    "pipe", "fifo", "kqueue", "crypto" };
373101044Sdes	int i;
374110148Srobert	int wid;
3751553Srgrimes
37697176Sdes	if (kd != NULL) {
37797378Sdes		if (kvm_read(kd, nl[NL_MAXFILES].n_value,
37897378Sdes			&maxf, sizeof maxf) != sizeof maxf ||
37997378Sdes		    kvm_read(kd, nl[NL_NFILES].n_value,
38097378Sdes			&openf, sizeof openf) != sizeof openf)
38197378Sdes			errx(1, "kvm_read(): %s", kvm_geterr(kd));
38297176Sdes	} else {
38397378Sdes		len = sizeof(int);
38497378Sdes		if (sysctlbyname("kern.maxfiles", &maxf, &len, 0, 0) == -1 ||
38597378Sdes		    sysctlbyname("kern.openfiles", &openf, &len, 0, 0) == -1)
38697176Sdes			err(1, "sysctlbyname()");
38797176Sdes	}
38897176Sdes
3891553Srgrimes	if (totalflag) {
39097378Sdes		(void)printf("%3d/%3d files\n", openf, maxf);
3911553Srgrimes		return;
3921553Srgrimes	}
3931553Srgrimes	if (getfiles(&buf, &len) == -1)
3941553Srgrimes		return;
395101044Sdes	openf = len / sizeof *fp;
396110148Srobert
39797378Sdes	(void)printf("%d/%d open files\n", openf, maxf);
398110148Srobert	printf(sizeof(uintptr_t) == 4 ? fhdr32 : fhdr64);
399110148Srobert	wid = (int)sizeof(uintptr_t) * 2;
400101044Sdes	for (fp = (struct xfile *)buf, i = 0; i < openf; ++fp, ++i) {
401110148Srobert		if ((size_t)fp->xf_type >= sizeof(dtypes) / sizeof(dtypes[0]))
4021553Srgrimes			continue;
403110148Srobert		(void)printf("%*jx", wid, (uintmax_t)(uintptr_t)fp->xf_file);
404110148Srobert		(void)printf(" %-6.6s", dtypes[fp->xf_type]);
4051553Srgrimes		fbp = flagbuf;
406101044Sdes		if (fp->xf_flag & FREAD)
4071553Srgrimes			*fbp++ = 'R';
408101044Sdes		if (fp->xf_flag & FWRITE)
4091553Srgrimes			*fbp++ = 'W';
410101044Sdes		if (fp->xf_flag & FAPPEND)
4111553Srgrimes			*fbp++ = 'A';
412101044Sdes		if (fp->xf_flag & FASYNC)
4131553Srgrimes			*fbp++ = 'I';
4141553Srgrimes		*fbp = '\0';
415110148Srobert		(void)printf(" %4s %3d", flagbuf, fp->xf_count);
416110148Srobert		(void)printf(" %3d", fp->xf_msgcount);
417110148Srobert		(void)printf(" %*jx", wid, (uintmax_t)(uintptr_t)fp->xf_data);
418110148Srobert		(void)printf(" %*jx\n", (int)sizeof(fp->xf_offset) * 2,
419110148Srobert		    (uintmax_t)fp->xf_offset);
4201553Srgrimes	}
4211553Srgrimes	free(buf);
4221553Srgrimes}
4231553Srgrimes
42497171Sdesstatic int
425194014Sstasgetfiles(struct xfile **abuf, size_t *alen)
4261553Srgrimes{
427194014Sstas	struct xfile *buf;
4281553Srgrimes	size_t len;
4291553Srgrimes	int mib[2];
4301553Srgrimes
4311553Srgrimes	/*
4321553Srgrimes	 * XXX
4331553Srgrimes	 * Add emulation of KINFO_FILE here.
4341553Srgrimes	 */
43597176Sdes	if (kd != NULL)
43630243Scharnier		errx(1, "files on dead kernel, not implemented");
4371553Srgrimes
4381553Srgrimes	mib[0] = CTL_KERN;
4391553Srgrimes	mib[1] = KERN_FILE;
4401553Srgrimes	if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
4411553Srgrimes		warn("sysctl: KERN_FILE");
4421553Srgrimes		return (-1);
4431553Srgrimes	}
4441553Srgrimes	if ((buf = malloc(len)) == NULL)
44530243Scharnier		errx(1, "malloc");
4461553Srgrimes	if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
4471553Srgrimes		warn("sysctl: KERN_FILE");
4481553Srgrimes		return (-1);
4491553Srgrimes	}
4501553Srgrimes	*abuf = buf;
4511553Srgrimes	*alen = len;
4521553Srgrimes	return (0);
4531553Srgrimes}
4541553Srgrimes
4551553Srgrimes/*
4561553Srgrimes * swapmode is based on a program called swapinfo written
4571553Srgrimes * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
4581553Srgrimes */
45997176Sdes
460143929Skeramida#define CONVERT(v)	((int64_t)(v) * pagesize / blocksize)
461196244Sstas#define CONVERT_BLOCKS(v)	((int64_t)(v) * pagesize)
46297176Sdesstatic struct kvm_swap swtot;
46397176Sdesstatic int nswdev;
46497176Sdes
46597171Sdesstatic void
46697176Sdesprint_swap_header(void)
4671553Srgrimes{
468108457Smike	int hlen;
46943046Sdillon	long blocksize;
47097176Sdes	const char *header;
4711553Srgrimes
4721553Srgrimes	header = getbsize(&hlen, &blocksize);
47397176Sdes	if (totalflag == 0)
474118275Sphk		(void)printf("%-15s %*s %8s %8s %8s\n",
475108457Smike		    "Device", hlen, header,
476118275Sphk		    "Used", "Avail", "Capacity");
47797176Sdes}
47842955Sdillon
47997176Sdesstatic void
480193978Sedprint_swap_line(const char *swdevname, intmax_t nblks, intmax_t bused,
481143929Skeramida    intmax_t bavail, float bpercent)
48297176Sdes{
483143929Skeramida	char usedbuf[5];
484143929Skeramida	char availbuf[5];
485108457Smike	int hlen, pagesize;
48697176Sdes	long blocksize;
48797176Sdes
48897176Sdes	pagesize = getpagesize();
48997176Sdes	getbsize(&hlen, &blocksize);
490143929Skeramida
491193978Sed	printf("%-15s %*jd ", swdevname, hlen, CONVERT(nblks));
492143929Skeramida	if (humanflag) {
493143929Skeramida		humanize_number(usedbuf, sizeof(usedbuf),
494196244Sstas		    CONVERT_BLOCKS(bused), "",
495143929Skeramida		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
496143929Skeramida		humanize_number(availbuf, sizeof(availbuf),
497196244Sstas		    CONVERT_BLOCKS(bavail), "",
498143929Skeramida		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
499143929Skeramida		printf("%8s %8s %5.0f%%\n", usedbuf, availbuf, bpercent);
500143929Skeramida	} else {
501143929Skeramida		printf("%8jd %8jd %5.0f%%\n", (intmax_t)CONVERT(bused),
502143929Skeramida		    (intmax_t)CONVERT(bavail), bpercent);
503143929Skeramida	}
504143929Skeramida}
505143929Skeramida
506143929Skeramidastatic void
507143929Skeramidaprint_swap(struct kvm_swap *ksw)
508143929Skeramida{
509143929Skeramida
51097176Sdes	swtot.ksw_total += ksw->ksw_total;
51197176Sdes	swtot.ksw_used += ksw->ksw_used;
51297176Sdes	++nswdev;
513143929Skeramida	if (totalflag == 0)
514143929Skeramida		print_swap_line(ksw->ksw_devname, ksw->ksw_total,
515152558Srwatson		    ksw->ksw_used, ksw->ksw_total - ksw->ksw_used,
516118275Sphk		    (ksw->ksw_used * 100.0) / ksw->ksw_total);
51797176Sdes}
51842955Sdillon
51997176Sdesstatic void
52097176Sdesprint_swap_total(void)
52197176Sdes{
522108457Smike	int hlen, pagesize;
52397176Sdes	long blocksize;
52497176Sdes
52597176Sdes	pagesize = getpagesize();
52697176Sdes	getbsize(&hlen, &blocksize);
52743046Sdillon	if (totalflag) {
52843046Sdillon		blocksize = 1024 * 1024;
529143929Skeramida		(void)printf("%jdM/%jdM swap space\n",
53097176Sdes		    CONVERT(swtot.ksw_used), CONVERT(swtot.ksw_total));
53197176Sdes	} else if (nswdev > 1) {
532143929Skeramida		print_swap_line("Total", swtot.ksw_total, swtot.ksw_used,
533143929Skeramida		    swtot.ksw_total - swtot.ksw_used,
53497176Sdes		    (swtot.ksw_used * 100.0) / swtot.ksw_total);
53597176Sdes	}
53697176Sdes}
5371553Srgrimes
53897176Sdesstatic void
53997176Sdesswapmode_kvm(void)
54097176Sdes{
54197176Sdes	struct kvm_swap kswap[16];
54297176Sdes	int i, n;
54397176Sdes
54497176Sdes	n = kvm_getswapinfo(kd, kswap, sizeof kswap / sizeof kswap[0],
545118278Sphk	    SWIF_DEV_PREFIX);
54697176Sdes
54797176Sdes	print_swap_header();
54897176Sdes	for (i = 0; i < n; ++i)
54997176Sdes		print_swap(&kswap[i]);
55097176Sdes	print_swap_total();
55197176Sdes}
55297176Sdes
55397176Sdesstatic void
55497176Sdesswapmode_sysctl(void)
55597176Sdes{
55697176Sdes	struct kvm_swap ksw;
55797176Sdes	struct xswdev xsw;
55897176Sdes	size_t mibsize, size;
55997176Sdes	int mib[16], n;
56097176Sdes
56197176Sdes	print_swap_header();
56297176Sdes	mibsize = sizeof mib / sizeof mib[0];
56397176Sdes	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
56497176Sdes		err(1, "sysctlnametomib()");
56597176Sdes	for (n = 0; ; ++n) {
56697176Sdes		mib[mibsize] = n;
56797176Sdes		size = sizeof xsw;
568126643Smarkm		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
56997176Sdes			break;
57097176Sdes		if (xsw.xsw_version != XSWDEV_VERSION)
57197176Sdes			errx(1, "xswdev version mismatch");
572115882Sphk		if (xsw.xsw_dev == NODEV)
573115882Sphk			snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
574115882Sphk			    "<NFSfile>");
575115882Sphk		else
576115882Sphk			snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
577115882Sphk			    "/dev/%s", devname(xsw.xsw_dev, S_IFCHR));
57897176Sdes		ksw.ksw_used = xsw.xsw_used;
57997176Sdes		ksw.ksw_total = xsw.xsw_nblks;
58097176Sdes		ksw.ksw_flags = xsw.xsw_flags;
58197176Sdes		print_swap(&ksw);
5821553Srgrimes	}
58397176Sdes	if (errno != ENOENT)
58497176Sdes		err(1, "sysctl()");
58597176Sdes	print_swap_total();
5861553Srgrimes}
58797176Sdes
58897176Sdesstatic void
58997176Sdesswapmode(void)
59097176Sdes{
59197176Sdes	if (kd != NULL)
59297176Sdes		swapmode_kvm();
59397176Sdes	else
59497176Sdes		swapmode_sysctl();
59597176Sdes}
596