pstat.c revision 181905
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: head/usr.sbin/pstat/pstat.c 181905 2008-08-20 08:31:58Z ed $");
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,
7997375Sdes	NL_TTY_LIST
8097375Sdes};
8197375Sdes
8297171Sdesstatic struct nlist nl[] = {
83143936Skeramida	{ .n_name = "_constty" },
84143936Skeramida	{ .n_name = "_maxfiles" },
85166696Sjhb	{ .n_name = "_openfiles" },
86143936Skeramida	{ .n_name = "_tty_list" },
87143936Skeramida	{ .n_name = "" }
881553Srgrimes};
891553Srgrimes
90143929Skeramidastatic int	humanflag;
9197171Sdesstatic int	usenumflag;
9297171Sdesstatic int	totalflag;
9397171Sdesstatic int	swapflag;
9497174Sdesstatic char	*nlistf;
9597174Sdesstatic char	*memf;
9697171Sdesstatic kvm_t	*kd;
971553Srgrimes
9897171Sdesstatic char	*usagestr;
998495Sphk
10097172Sdesstatic void	filemode(void);
10197367Sdesstatic int	getfiles(char **, size_t *);
10297172Sdesstatic void	swapmode(void);
10397172Sdesstatic void	ttymode(void);
10497367Sdesstatic void	ttyprt(struct xtty *);
10597172Sdesstatic void	usage(void);
1061553Srgrimes
1071553Srgrimesint
10897172Sdesmain(int argc, char *argv[])
1091553Srgrimes{
1101553Srgrimes	int ch, i, quit, ret;
11197173Sdes	int fileflag, ttyflag;
1128495Sphk	char buf[_POSIX2_LINE_MAX],*opts;
1131553Srgrimes
11497173Sdes	fileflag = swapflag = ttyflag = 0;
1158495Sphk
1168495Sphk	/* We will behave like good old swapinfo if thus invoked */
11797378Sdes	opts = strrchr(argv[0], '/');
1188495Sphk	if (opts)
1198495Sphk		opts++;
1208495Sphk	else
1218495Sphk		opts = argv[0];
12297378Sdes	if (!strcmp(opts, "swapinfo")) {
1238495Sphk		swapflag = 1;
124168227Smarkm		opts = "ghkmM:N:";
125168227Smarkm		usagestr = "swapinfo [-ghkm] [-M core [-N system]]";
1268495Sphk	} else {
127168292Sru		opts = "TM:N:fghkmnst";
128168292Sru		usagestr = "pstat [-Tfghkmnst] [-M core [-N system]]";
1298495Sphk	}
1308495Sphk
13124428Simp	while ((ch = getopt(argc, argv, opts)) != -1)
1321553Srgrimes		switch (ch) {
1331553Srgrimes		case 'f':
1341553Srgrimes			fileflag = 1;
1351553Srgrimes			break;
136168227Smarkm		case 'g':
137171195Sscf			setenv("BLOCKSIZE", "1G", 1);
138168227Smarkm			break;
139143929Skeramida		case 'h':
140143929Skeramida			humanflag = 1;
141143929Skeramida			break;
1428495Sphk		case 'k':
143171195Sscf			setenv("BLOCKSIZE", "1K", 1);
1448495Sphk			break;
145168227Smarkm		case 'm':
146171195Sscf			setenv("BLOCKSIZE", "1M", 1);
147168227Smarkm			break;
1481553Srgrimes		case 'M':
1491553Srgrimes			memf = optarg;
1501553Srgrimes			break;
1511553Srgrimes		case 'N':
1521553Srgrimes			nlistf = optarg;
1531553Srgrimes			break;
1541553Srgrimes		case 'n':
1551553Srgrimes			usenumflag = 1;
1561553Srgrimes			break;
1571553Srgrimes		case 's':
15842955Sdillon			++swapflag;
1591553Srgrimes			break;
1601553Srgrimes		case 'T':
1611553Srgrimes			totalflag = 1;
1621553Srgrimes			break;
1631553Srgrimes		case 't':
1641553Srgrimes			ttyflag = 1;
1651553Srgrimes			break;
1661553Srgrimes		default:
16730243Scharnier			usage();
1681553Srgrimes		}
1691553Srgrimes	argc -= optind;
1701553Srgrimes	argv += optind;
1711553Srgrimes
17297176Sdes	if (memf != NULL) {
17397176Sdes		kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
17497176Sdes		if (kd == NULL)
17597176Sdes			errx(1, "kvm_openfiles: %s", buf);
17697176Sdes		if ((ret = kvm_nlist(kd, nl)) != 0) {
17797176Sdes			if (ret == -1)
17897176Sdes				errx(1, "kvm_nlist: %s", kvm_geterr(kd));
17997176Sdes			quit = 0;
18097375Sdes			for (i = 0; nl[i].n_name[0] != '\0'; ++i)
18197375Sdes				if (nl[i].n_value == 0) {
18297176Sdes					quit = 1;
18397176Sdes					warnx("undefined symbol: %s",
18497176Sdes					    nl[i].n_name);
18597176Sdes				}
18697176Sdes			if (quit)
18797176Sdes				exit(1);
18897176Sdes		}
1891553Srgrimes	}
19097173Sdes	if (!(fileflag | ttyflag | swapflag | totalflag))
19130243Scharnier		usage();
1921553Srgrimes	if (fileflag || totalflag)
1931553Srgrimes		filemode();
1941553Srgrimes	if (ttyflag)
1951553Srgrimes		ttymode();
1961553Srgrimes	if (swapflag || totalflag)
1971553Srgrimes		swapmode();
1981553Srgrimes	exit (0);
1991553Srgrimes}
2001553Srgrimes
20130243Scharnierstatic void
20297172Sdesusage(void)
20330243Scharnier{
20430243Scharnier	fprintf(stderr, "usage: %s\n", usagestr);
20530243Scharnier	exit (1);
20630243Scharnier}
20730243Scharnier
208110148Srobertstatic const char fhdr32[] =
209110148Srobert  "   LOC   TYPE   FLG  CNT MSG   DATA        OFFSET\n";
210110148Srobert/* c0000000 ------ RWAI 123 123 c0000000 1000000000000000 */
211110148Srobert
212110148Srobertstatic const char fhdr64[] =
213110148Srobert  "       LOC       TYPE   FLG  CNT MSG       DATA            OFFSET\n";
214110148Srobert/* c000000000000000 ------ RWAI 123 123 c000000000000000 1000000000000000 */
215110148Srobert
21697171Sdesstatic const char hdr[] =
217181905Sed"      LINE   INQ  CAN  LIN  LOW  OUTQ  USE  LOW   COL  SESS  PGID STATE\n";
2181553Srgrimes
21997171Sdesstatic void
22097375Sdesttymode_kvm(void)
2211553Srgrimes{
222130267Sphk	TAILQ_HEAD(, tty) tl;
22397375Sdes	struct tty *tp, tty;
22497375Sdes	struct xtty xt;
22597375Sdes
22697375Sdes	(void)printf("%s", hdr);
22797375Sdes	bzero(&xt, sizeof xt);
22897375Sdes	xt.xt_size = sizeof xt;
22997375Sdes	if (kvm_read(kd, nl[NL_TTY_LIST].n_value, &tl, sizeof tl) != sizeof tl)
23097375Sdes		errx(1, "kvm_read(): %s", kvm_geterr(kd));
231130267Sphk	tp = TAILQ_FIRST(&tl);
23297375Sdes	while (tp != NULL) {
23397375Sdes		if (kvm_read(kd, (u_long)tp, &tty, sizeof tty) != sizeof tty)
23497375Sdes			errx(1, "kvm_read(): %s", kvm_geterr(kd));
235181905Sed		xt.xt_insize = tty.t_inq.ti_nblocks * TTYINQ_DATASIZE;
236181905Sed		xt.xt_incc = tty.t_inq.ti_linestart - tty.t_inq.ti_begin;
237181905Sed		xt.xt_inlc = tty.t_inq.ti_end - tty.t_inq.ti_linestart;
238181905Sed		xt.xt_inlow = tty.t_inlow;
239181905Sed		xt.xt_outsize = tty.t_outq.to_nblocks * TTYOUTQ_DATASIZE;
240181905Sed		xt.xt_outcc = tty.t_outq.to_end - tty.t_outq.to_begin;
241181905Sed		xt.xt_outlow = tty.t_outlow;
242181905Sed		xt.xt_column = tty.t_column;
243181905Sed		/* xt.xt_pgid = ... */
244181905Sed		/* xt.xt_sid = ... */
245181905Sed		xt.xt_flags = tty.t_flags;
246181905Sed		xt.xt_dev = NODEV;
24797375Sdes		ttyprt(&xt);
248178987Sremko		tp = TAILQ_NEXT(&tty, t_list);
24997375Sdes	}
25097375Sdes}
25197375Sdes
25297375Sdesstatic void
25397375Sdesttymode_sysctl(void)
25497375Sdes{
25597367Sdes	struct xtty *xt, *end;
25697367Sdes	void *xttys;
25797367Sdes	size_t len;
2581553Srgrimes
25978378Sdd	(void)printf("%s", hdr);
26097367Sdes	if ((xttys = malloc(len = sizeof *xt)) == NULL)
26197367Sdes		err(1, "malloc()");
26297367Sdes	while (sysctlbyname("kern.ttys", xttys, &len, 0, 0) == -1) {
26397367Sdes		if (errno != ENOMEM)
26497367Sdes			err(1, "sysctlbyname()");
26597367Sdes		len *= 2;
26697367Sdes		if ((xttys = realloc(xttys, len)) == NULL)
26797367Sdes			err(1, "realloc()");
26849539Sphk	}
26997367Sdes	if (len > 0) {
27097367Sdes		end = (struct xtty *)((char *)xttys + len);
27197367Sdes		for (xt = xttys; xt < end; xt++)
27297367Sdes			ttyprt(xt);
27397367Sdes	}
2741553Srgrimes}
2751553Srgrimes
27697171Sdesstatic void
27797375Sdesttymode(void)
2781553Srgrimes{
2791553Srgrimes
28097375Sdes	if (kd != NULL)
28197375Sdes		ttymode_kvm();
28297375Sdes	else
28397375Sdes		ttymode_sysctl();
2841553Srgrimes}
2851553Srgrimes
28697171Sdesstatic struct {
2871553Srgrimes	int flag;
2881553Srgrimes	char val;
2891553Srgrimes} ttystates[] = {
290181905Sed#if 0
291181905Sed	{ TF_NOPREFIX,	'N' },
2929620Sbde#endif
293181905Sed	{ TF_INITLOCK,	'I' },
294181905Sed	{ TF_CALLOUT,	'C' },
295181905Sed
296181905Sed	/* Keep these together -> 'Oi' and 'Oo'. */
297181905Sed	{ TF_OPENED,	'O' },
298181905Sed	{ TF_OPENED_IN,	'i' },
299181905Sed	{ TF_OPENED_OUT,'o' },
300181905Sed
301181905Sed	{ TF_GONE,	'G' },
302181905Sed	{ TF_OPENCLOSE,	'B' },
303181905Sed	{ TF_ASYNC,	'Y' },
304181905Sed	{ TF_LITERAL,	'L' },
305181905Sed
306181905Sed	/* Keep these together -> 'Hi' and 'Ho'. */
307181905Sed	{ TF_HIWAT,	'H' },
308181905Sed	{ TF_HIWAT_IN,	'i' },
309181905Sed	{ TF_HIWAT_OUT,	'o' },
310181905Sed
311181905Sed	{ TF_STOPPED,	'S' },
312181905Sed	{ TF_EXCLUDE,	'X' },
313181905Sed	{ TF_BYPASS,	'l' },
314181905Sed	{ TF_ZOMBIE,	'Z' },
315181905Sed
316181905Sed	{ 0,	       '\0' },
3171553Srgrimes};
3181553Srgrimes
31997171Sdesstatic void
32097367Sdesttyprt(struct xtty *xt)
3211553Srgrimes{
32223687Speter	int i, j;
323181905Sed	char *name;
3241553Srgrimes
32597367Sdes	if (xt->xt_size != sizeof *xt)
32697367Sdes		errx(1, "struct xtty size mismatch");
32797367Sdes	if (usenumflag || xt->xt_dev == 0 ||
32897367Sdes	   (name = devname(xt->xt_dev, S_IFCHR)) == NULL)
329181905Sed		printf("%5d,%4d ", major(xt->xt_dev), minor(xt->xt_dev));
3301553Srgrimes	else
331181905Sed		printf("%10s ", name);
332181905Sed	printf("%5zu %4zu %4zu %4zu %5zu %4zu %4zu %5u %5d %5d ",
333181905Sed	    xt->xt_insize, xt->xt_incc, xt->xt_inlc,
334181905Sed	    (xt->xt_insize - xt->xt_inlow), xt->xt_outsize,
335181905Sed	    xt->xt_outcc, (xt->xt_outsize - xt->xt_outlow),
336181905Sed	    xt->xt_column, xt->xt_sid, xt->xt_pgid);
3371553Srgrimes	for (i = j = 0; ttystates[i].flag; i++)
338181905Sed		if (xt->xt_flags & ttystates[i].flag) {
339181905Sed			putchar(ttystates[i].val);
340181905Sed			j++;
341181905Sed		}
3421553Srgrimes	if (j == 0)
343181905Sed		putchar('-');
344181905Sed	putchar('\n');
3451553Srgrimes}
3461553Srgrimes
34797171Sdesstatic void
34897172Sdesfilemode(void)
3491553Srgrimes{
350101044Sdes	struct xfile *fp;
3511553Srgrimes	char *buf, flagbuf[16], *fbp;
35297378Sdes	int maxf, openf;
35397176Sdes	size_t len;
354110148Srobert	static char *dtypes[] = { "???", "inode", "socket", "pipe",
355110148Srobert	    "fifo", "kqueue", "crypto" };
356101044Sdes	int i;
357110148Srobert	int wid;
3581553Srgrimes
35997176Sdes	if (kd != NULL) {
36097378Sdes		if (kvm_read(kd, nl[NL_MAXFILES].n_value,
36197378Sdes			&maxf, sizeof maxf) != sizeof maxf ||
36297378Sdes		    kvm_read(kd, nl[NL_NFILES].n_value,
36397378Sdes			&openf, sizeof openf) != sizeof openf)
36497378Sdes			errx(1, "kvm_read(): %s", kvm_geterr(kd));
36597176Sdes	} else {
36697378Sdes		len = sizeof(int);
36797378Sdes		if (sysctlbyname("kern.maxfiles", &maxf, &len, 0, 0) == -1 ||
36897378Sdes		    sysctlbyname("kern.openfiles", &openf, &len, 0, 0) == -1)
36997176Sdes			err(1, "sysctlbyname()");
37097176Sdes	}
37197176Sdes
3721553Srgrimes	if (totalflag) {
37397378Sdes		(void)printf("%3d/%3d files\n", openf, maxf);
3741553Srgrimes		return;
3751553Srgrimes	}
3761553Srgrimes	if (getfiles(&buf, &len) == -1)
3771553Srgrimes		return;
378101044Sdes	openf = len / sizeof *fp;
379110148Srobert
38097378Sdes	(void)printf("%d/%d open files\n", openf, maxf);
381110148Srobert	printf(sizeof(uintptr_t) == 4 ? fhdr32 : fhdr64);
382110148Srobert	wid = (int)sizeof(uintptr_t) * 2;
383101044Sdes	for (fp = (struct xfile *)buf, i = 0; i < openf; ++fp, ++i) {
384110148Srobert		if ((size_t)fp->xf_type >= sizeof(dtypes) / sizeof(dtypes[0]))
3851553Srgrimes			continue;
386110148Srobert		(void)printf("%*jx", wid, (uintmax_t)(uintptr_t)fp->xf_file);
387110148Srobert		(void)printf(" %-6.6s", dtypes[fp->xf_type]);
3881553Srgrimes		fbp = flagbuf;
389101044Sdes		if (fp->xf_flag & FREAD)
3901553Srgrimes			*fbp++ = 'R';
391101044Sdes		if (fp->xf_flag & FWRITE)
3921553Srgrimes			*fbp++ = 'W';
393101044Sdes		if (fp->xf_flag & FAPPEND)
3941553Srgrimes			*fbp++ = 'A';
395101044Sdes		if (fp->xf_flag & FASYNC)
3961553Srgrimes			*fbp++ = 'I';
3971553Srgrimes		*fbp = '\0';
398110148Srobert		(void)printf(" %4s %3d", flagbuf, fp->xf_count);
399110148Srobert		(void)printf(" %3d", fp->xf_msgcount);
400110148Srobert		(void)printf(" %*jx", wid, (uintmax_t)(uintptr_t)fp->xf_data);
401110148Srobert		(void)printf(" %*jx\n", (int)sizeof(fp->xf_offset) * 2,
402110148Srobert		    (uintmax_t)fp->xf_offset);
4031553Srgrimes	}
4041553Srgrimes	free(buf);
4051553Srgrimes}
4061553Srgrimes
40797171Sdesstatic int
40897367Sdesgetfiles(char **abuf, size_t *alen)
4091553Srgrimes{
4101553Srgrimes	size_t len;
4111553Srgrimes	int mib[2];
4121553Srgrimes	char *buf;
4131553Srgrimes
4141553Srgrimes	/*
4151553Srgrimes	 * XXX
4161553Srgrimes	 * Add emulation of KINFO_FILE here.
4171553Srgrimes	 */
41897176Sdes	if (kd != NULL)
41930243Scharnier		errx(1, "files on dead kernel, not implemented");
4201553Srgrimes
4211553Srgrimes	mib[0] = CTL_KERN;
4221553Srgrimes	mib[1] = KERN_FILE;
4231553Srgrimes	if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
4241553Srgrimes		warn("sysctl: KERN_FILE");
4251553Srgrimes		return (-1);
4261553Srgrimes	}
4271553Srgrimes	if ((buf = malloc(len)) == NULL)
42830243Scharnier		errx(1, "malloc");
4291553Srgrimes	if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
4301553Srgrimes		warn("sysctl: KERN_FILE");
4311553Srgrimes		return (-1);
4321553Srgrimes	}
4331553Srgrimes	*abuf = buf;
4341553Srgrimes	*alen = len;
4351553Srgrimes	return (0);
4361553Srgrimes}
4371553Srgrimes
4381553Srgrimes/*
4391553Srgrimes * swapmode is based on a program called swapinfo written
4401553Srgrimes * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
4411553Srgrimes */
44297176Sdes
443143929Skeramida#define CONVERT(v)	((int64_t)(v) * pagesize / blocksize)
44497176Sdesstatic struct kvm_swap swtot;
44597176Sdesstatic int nswdev;
44697176Sdes
44797171Sdesstatic void
44897176Sdesprint_swap_header(void)
4491553Srgrimes{
450108457Smike	int hlen;
45143046Sdillon	long blocksize;
45297176Sdes	const char *header;
4531553Srgrimes
4541553Srgrimes	header = getbsize(&hlen, &blocksize);
45597176Sdes	if (totalflag == 0)
456118275Sphk		(void)printf("%-15s %*s %8s %8s %8s\n",
457108457Smike		    "Device", hlen, header,
458118275Sphk		    "Used", "Avail", "Capacity");
45997176Sdes}
46042955Sdillon
46197176Sdesstatic void
462143929Skeramidaprint_swap_line(const char *devname, intmax_t nblks, intmax_t bused,
463143929Skeramida    intmax_t bavail, float bpercent)
46497176Sdes{
465143929Skeramida	char usedbuf[5];
466143929Skeramida	char availbuf[5];
467108457Smike	int hlen, pagesize;
46897176Sdes	long blocksize;
46997176Sdes
47097176Sdes	pagesize = getpagesize();
47197176Sdes	getbsize(&hlen, &blocksize);
472143929Skeramida
473143929Skeramida	printf("%-15s %*jd ", devname, hlen, CONVERT(nblks));
474143929Skeramida	if (humanflag) {
475143929Skeramida		humanize_number(usedbuf, sizeof(usedbuf),
476143929Skeramida		    CONVERT(blocksize * bused), "",
477143929Skeramida		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
478143929Skeramida		humanize_number(availbuf, sizeof(availbuf),
479143929Skeramida		    CONVERT(blocksize * bavail), "",
480143929Skeramida		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
481143929Skeramida		printf("%8s %8s %5.0f%%\n", usedbuf, availbuf, bpercent);
482143929Skeramida	} else {
483143929Skeramida		printf("%8jd %8jd %5.0f%%\n", (intmax_t)CONVERT(bused),
484143929Skeramida		    (intmax_t)CONVERT(bavail), bpercent);
485143929Skeramida	}
486143929Skeramida}
487143929Skeramida
488143929Skeramidastatic void
489143929Skeramidaprint_swap(struct kvm_swap *ksw)
490143929Skeramida{
491143929Skeramida
49297176Sdes	swtot.ksw_total += ksw->ksw_total;
49397176Sdes	swtot.ksw_used += ksw->ksw_used;
49497176Sdes	++nswdev;
495143929Skeramida	if (totalflag == 0)
496143929Skeramida		print_swap_line(ksw->ksw_devname, ksw->ksw_total,
497152558Srwatson		    ksw->ksw_used, ksw->ksw_total - ksw->ksw_used,
498118275Sphk		    (ksw->ksw_used * 100.0) / ksw->ksw_total);
49997176Sdes}
50042955Sdillon
50197176Sdesstatic void
50297176Sdesprint_swap_total(void)
50397176Sdes{
504108457Smike	int hlen, pagesize;
50597176Sdes	long blocksize;
50697176Sdes
50797176Sdes	pagesize = getpagesize();
50897176Sdes	getbsize(&hlen, &blocksize);
50943046Sdillon	if (totalflag) {
51043046Sdillon		blocksize = 1024 * 1024;
511143929Skeramida		(void)printf("%jdM/%jdM swap space\n",
51297176Sdes		    CONVERT(swtot.ksw_used), CONVERT(swtot.ksw_total));
51397176Sdes	} else if (nswdev > 1) {
514143929Skeramida		print_swap_line("Total", swtot.ksw_total, swtot.ksw_used,
515143929Skeramida		    swtot.ksw_total - swtot.ksw_used,
51697176Sdes		    (swtot.ksw_used * 100.0) / swtot.ksw_total);
51797176Sdes	}
51897176Sdes}
5191553Srgrimes
52097176Sdesstatic void
52197176Sdesswapmode_kvm(void)
52297176Sdes{
52397176Sdes	struct kvm_swap kswap[16];
52497176Sdes	int i, n;
52597176Sdes
52697176Sdes	n = kvm_getswapinfo(kd, kswap, sizeof kswap / sizeof kswap[0],
527118278Sphk	    SWIF_DEV_PREFIX);
52897176Sdes
52997176Sdes	print_swap_header();
53097176Sdes	for (i = 0; i < n; ++i)
53197176Sdes		print_swap(&kswap[i]);
53297176Sdes	print_swap_total();
53397176Sdes}
53497176Sdes
53597176Sdesstatic void
53697176Sdesswapmode_sysctl(void)
53797176Sdes{
53897176Sdes	struct kvm_swap ksw;
53997176Sdes	struct xswdev xsw;
54097176Sdes	size_t mibsize, size;
54197176Sdes	int mib[16], n;
54297176Sdes
54397176Sdes	print_swap_header();
54497176Sdes	mibsize = sizeof mib / sizeof mib[0];
54597176Sdes	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
54697176Sdes		err(1, "sysctlnametomib()");
54797176Sdes	for (n = 0; ; ++n) {
54897176Sdes		mib[mibsize] = n;
54997176Sdes		size = sizeof xsw;
550126643Smarkm		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
55197176Sdes			break;
55297176Sdes		if (xsw.xsw_version != XSWDEV_VERSION)
55397176Sdes			errx(1, "xswdev version mismatch");
554115882Sphk		if (xsw.xsw_dev == NODEV)
555115882Sphk			snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
556115882Sphk			    "<NFSfile>");
557115882Sphk		else
558115882Sphk			snprintf(ksw.ksw_devname, sizeof ksw.ksw_devname,
559115882Sphk			    "/dev/%s", devname(xsw.xsw_dev, S_IFCHR));
56097176Sdes		ksw.ksw_used = xsw.xsw_used;
56197176Sdes		ksw.ksw_total = xsw.xsw_nblks;
56297176Sdes		ksw.ksw_flags = xsw.xsw_flags;
56397176Sdes		print_swap(&ksw);
5641553Srgrimes	}
56597176Sdes	if (errno != ENOENT)
56697176Sdes		err(1, "sysctl()");
56797176Sdes	print_swap_total();
5681553Srgrimes}
56997176Sdes
57097176Sdesstatic void
57197176Sdesswapmode(void)
57297176Sdes{
57397176Sdes	if (kd != NULL)
57497176Sdes		swapmode_kvm();
57597176Sdes	else
57697176Sdes		swapmode_sysctl();
57797176Sdes}
578