summaryrefslogtreecommitdiffstats
path: root/usr.sbin/swapinfo/swapinfo.c
blob: 7a8d12c8a4b7fc5767c792c2d89cf3a635cfb6fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
 * swapinfo
 *
 * Swapinfo will provide some information about the state of the swap
 * space for the system.  It'll determine the number of swap areas,
 * their original size, and their utilization.
 *
 * Kevin Lahey, February 16, 1993
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/rlist.h>
#include <nlist.h>
#include <kvm.h>

struct rlist *swaplist;

static struct nlist nl[] = {{"_swaplist"},  /* list of free swap areas */
#define VM_SWAPMAP	0
			    {"_swdevt"},   /* list of swap devices and sizes */
#define VM_SWDEVT	1
			    {"_nswap"},    /* size of largest swap device */
#define VM_NSWAP	2
			    {"_nswdev"},   /* number of swap devices */
#define VM_NSWDEV	3
			    {"_dmmax"},    /* maximum size of a swap block */
#define VM_DMMAX	4
			    {""}};

char    *getbsize __P((int *, long *));
void	 usage __P((void));

main (argc, argv)
int	argc;
char	**argv;
{
	int	i, total_avail, total_free, total_partitions, *by_device, 
		nswap, nswdev, dmmax, ch;
	struct swdevt	*swdevt;
	struct rlist	head;
	static long blocksize;
        static int headerlen;
        static char *header;
        char  **save;
	kvm_t *kd;

	/* We are trying to be simple here: */

	save = argv;
	while ((ch = getopt(argc, argv, "k")) != EOF)
		switch(ch) {
		case 'k':
			putenv("BLOCKSIZE=1k");
			break;
		case '?':
		default:
			usage();
		}
	argv += optind;

	if (!*argv) {
		argv = save;
		argv[0] = ".";
		argv[1] = NULL;
	}

	/* Open up /dev/kmem for reading. */
	
	if ((kd = kvm_openfiles(NULL, NULL, NULL, NULL, NULL)) == (kvm_t *)0) {
		fprintf (stderr, "%s: kvm_openfiles:  %s\n", 
			 argv [0], kvm_geterr(kd));
		exit (1);
	}

	/* Figure out the offset of the various structures we'll need. */

	if (kvm_nlist(kd, nl) == -1) {
		fprintf (stderr, "%s: kvm_nlist:  %s\n", 
			 argv [0], kvm_geterr(kd));
		exit (1);
	}

	if (kvm_read(kd, nl[VM_NSWAP].n_value, &nswap, sizeof (nswap)) !=
	    sizeof (nswap)) {
		fprintf (stderr, "%s:  didn't read all of nswap\n", 
			 argv [0]);
		exit (5);
	}

	if (kvm_read(kd, nl[VM_NSWDEV].n_value, &nswdev, sizeof (nswdev)) !=
	    sizeof (nswdev)) {
		fprintf (stderr, "%s:  didn't read all of nswdev\n", 
			 argv [0]);
		exit (5);
	}

	if (kvm_read(kd, nl[VM_DMMAX].n_value, &dmmax, sizeof (dmmax)) !=
	    sizeof (dmmax)) {
		fprintf (stderr, "%s:  didn't read all of dmmax\n", 
			 argv [0]);
		exit (5);
	}

	if ((swdevt = malloc (sizeof (struct swdevt) * nswdev)) == NULL ||
	    (by_device = calloc (sizeof (*by_device), nswdev)) == NULL) {
		perror ("malloc");
		exit (5);
	}

	if (kvm_read(kd, nl[VM_SWDEVT].n_value, swdevt, 
		      sizeof (struct swdevt) * nswdev) !=
	    sizeof (struct swdevt) * nswdev) {
		fprintf (stderr, "%s:  didn't read all of swdevt\n", 
			 argv [0]);
		exit (5);
	}

	if (kvm_read(kd, nl[0].n_value, &swaplist, sizeof (struct rlist *)) !=
	    sizeof (struct rlist *)) {
		fprintf (stderr, "%s:  didn't read all of swaplist\n", 
			 argv [0]);
		exit (5);
	}

	/* Traverse the list of free swap space... */

	total_free = 0;
    	while (swaplist) {
		int	top, bottom, next_block;

		if (kvm_read(kd, (long) swaplist, &head, sizeof (struct rlist )) !=
		    sizeof (struct rlist )) {
			fprintf (stderr, "%s:  didn't read all of head\n", 
				 argv [0]);
			exit (5);
		}

		top = head.rl_end;
		bottom = head.rl_start;

		total_free += top - bottom + 1;

		/*
		 * Swap space is split up among the configured disk.
		 * The first dmmax blocks of swap space some from the
		 * first disk, the next dmmax blocks from the next, 
		 * and so on.  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.
		 */

		while (top / dmmax != bottom / dmmax) {
			next_block = ((bottom + dmmax) / dmmax);
			by_device [(bottom / dmmax) % nswdev] +=
				next_block * dmmax - bottom;
			bottom = next_block * dmmax;
		}

		by_device [(bottom / dmmax) % nswdev] +=
			top - bottom + 1;

		swaplist = head.rl_next;
	}

	header = getbsize(&headerlen, &blocksize);
	printf ("%-10s %10s %10s %10s %10s\n",
		"Device", header, "Used", "Available", "Capacity");
	for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
		printf ("/dev/%-5s %10d ",
			devname (swdevt [i].sw_dev, S_IFBLK), 
			swdevt [i].sw_nblks / (blocksize/512));

		/*
		 * Don't report statistics for partitions which have not
		 * yet been activated via swapon(8).
		 */

		if (!swdevt [i].sw_freed) {
			printf (" *** not available for swapping ***\n");
		} else {
			total_partitions++;
			total_avail += swdevt [i].sw_nblks;
			printf ("%10d %10d %7.0f%%\n", 
				(swdevt [i].sw_nblks - by_device [i]) / (blocksize/512),
				by_device [i] / (blocksize/512),
				(double) (swdevt [i].sw_nblks - 
					  by_device [i]) / 
				(double) swdevt [i].sw_nblks * 100.0);
		}
	}

	/* 
	 * If only one partition has been set up via swapon(8), we don't
	 * need to bother with totals.
	 */

	if (total_partitions > 1)
		printf ("%-10s %10d %10d %10d %7.0f%%\n", "Total", 
			total_avail / (blocksize/512), 
			(total_avail - total_free) / (blocksize/512), 
			total_free / (blocksize/512),
			(double) (total_avail - total_free) / 
			(double) total_avail * 100.0);

	exit (0);
}

void
usage()
{
	(void)fprintf(stderr, "usage: swapinfo [-k]\n");
	exit(1);
}


OpenPOWER on IntegriCloud