fts(3) updates
[unix-history] / usr.sbin / swapinfo / swapinfo.c
CommitLineData
4d554349
NW
1/*
2 * swapinfo
3 *
4 * Swapinfo will provide some information about the state of the swap
5 * space for the system. It'll determine the number of swap areas,
6 * their original size, and their utilization.
7 *
8 * Kevin Lahey, February 16, 1993
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/types.h>
14#include <sys/ioctl.h>
15#include <sys/termios.h>
16#include <sys/stat.h>
17#include <sys/tty.h>
18#include <sys/uio.h>
19#include <sys/buf.h>
20#include <sys/conf.h>
21#include <sys/rlist.h> /* swapmap defined here... */
22#include <nlist.h>
23
24
25static struct nlist nl[] = {{"_swapmap"}, /* list of free swap areas */
26#define VM_SWAPMAP 0
27 {"_swdevt"}, /* list of swap devices and sizes */
28#define VM_SWDEVT 1
29 {"_nswap"}, /* size of largest swap device */
30#define VM_NSWAP 2
31 {"_nswdev"}, /* number of swap devices */
32#define VM_NSWDEV 3
33 {"_dmmax"}, /* maximum size of a swap block */
34#define VM_DMMAX 4
35 {""}};
36
4e97a0eb 37char *getbsize __P((char *, int *, long *));
4d554349
NW
38
39main (argc, argv)
40int argc;
41char **argv;
42{
43 int i, total_avail, total_free, total_partitions, *by_device,
44 use_k = 1, /* used as a divisor, so 1 == blocks, 2 == K */
45 nswap, nswdev, dmmax;
46 struct swdevt *swdevt;
47 struct rlist head;
4e97a0eb
NW
48 static long blocksize;
49 static int headerlen;
50 static char *header;
4d554349
NW
51
52 /* We are trying to be simple here: */
53
54 if (argc > 1)
4e97a0eb
NW
55 {
56 fprintf (stderr, "Usage: swapinfo\n");
57 exit (1);
58 }
4d554349
NW
59
60 /* Open up /dev/kmem for reading. */
61
62 if (kvm_openfiles (NULL, NULL, NULL) == -1) {
63 fprintf (stderr, "%s: kvm_openfiles: %s\n",
64 argv [0], kvm_geterr());
65 exit (1);
66 }
67
68 /* Figure out the offset of the various structures we'll need. */
69
70 if (kvm_nlist (nl) == -1) {
71 fprintf (stderr, "%s: kvm_nlist: %s\n",
72 argv [0], kvm_geterr());
73 exit (1);
74 }
75
76 if (kvm_read (nl [VM_NSWAP].n_value, &nswap, sizeof (nswap)) !=
77 sizeof (nswap)) {
78 fprintf (stderr, "%s: didn't read all of nswap\n",
79 argv [0]);
80 exit (5);
81 }
82
83 if (kvm_read (nl [VM_NSWDEV].n_value, &nswdev, sizeof (nswdev)) !=
84 sizeof (nswdev)) {
85 fprintf (stderr, "%s: didn't read all of nswdev\n",
86 argv [0]);
87 exit (5);
88 }
89
90 if (kvm_read (nl [VM_DMMAX].n_value, &dmmax, sizeof (dmmax)) !=
91 sizeof (dmmax)) {
92 fprintf (stderr, "%s: didn't read all of dmmax\n",
93 argv [0]);
94 exit (5);
95 }
96
97 if ((swdevt = malloc (sizeof (struct swdevt) * nswdev)) == NULL ||
98 (by_device = calloc (sizeof (*by_device), nswdev)) == NULL) {
99 perror ("malloc");
100 exit (5);
101 }
102
103 if (kvm_read (nl [VM_SWDEVT].n_value, swdevt,
104 sizeof (struct swdevt) * nswdev) !=
105 sizeof (struct swdevt) * nswdev) {
106 fprintf (stderr, "%s: didn't read all of swdevt\n",
107 argv [0]);
108 exit (5);
109 }
110
111 if (kvm_read (nl [0].n_value, &swapmap, sizeof (struct rlist *)) !=
112 sizeof (struct rlist *)) {
113 fprintf (stderr, "%s: didn't read all of swapmap\n",
114 argv [0]);
115 exit (5);
116 }
117
118 /* Traverse the list of free swap space... */
119
120 total_free = 0;
121 while (swapmap) {
122 int top, bottom, next_block;
123
124 if (kvm_read ((long) swapmap, &head, sizeof (struct rlist )) !=
125 sizeof (struct rlist )) {
126 fprintf (stderr, "%s: didn't read all of head\n",
127 argv [0]);
128 exit (5);
129 }
130
131 top = head.rl_end;
132 bottom = head.rl_start;
133
134 total_free += top - bottom + 1;
135
136 /*
137 * Swap space is split up among the configured disk.
138 * The first dmmax blocks of swap space some from the
139 * first disk, the next dmmax blocks from the next,
140 * and so on. The list of free space joins adjacent
141 * free blocks, ignoring device boundries. If we want
142 * to keep track of this information per device, we'll
143 * just have to extract it ourselves.
144 */
145
146 while (top / dmmax != bottom / dmmax) {
147 next_block = ((bottom + dmmax) / dmmax);
148 by_device [(bottom / dmmax) % nswdev] +=
149 next_block * dmmax - bottom;
150 bottom = next_block * dmmax;
151 }
152
153 by_device [(bottom / dmmax) % nswdev] +=
154 top - bottom + 1;
155
156 swapmap = head.rl_next;
157 }
158
4e97a0eb 159 header = getbsize("swapinfo", &headerlen, &blocksize);
4d554349 160 printf ("%-10s %10s %10s %10s %10s\n",
4e97a0eb 161 "Device", header, "Used", "Available", "Capacity");
4d554349
NW
162 for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
163 printf ("/dev/%-5s %10d ",
164 devname (swdevt [i].sw_dev, S_IFBLK),
165 swdevt [i].sw_nblks / use_k);
166
167 /*
168 * Don't report statistics for partitions which have not
169 * yet been activated via swapon(8).
170 */
171
172 if (!swdevt [i].sw_freed) {
173 printf (" *** not available for swapping ***\n");
174 } else {
175 total_partitions++;
176 total_avail += swdevt [i].sw_nblks;
177 printf ("%10d %10d %7.0f%%\n",
178 (swdevt [i].sw_nblks - by_device [i]) / use_k,
179 by_device [i] / use_k,
180 (double) (swdevt [i].sw_nblks -
181 by_device [i]) /
182 (double) swdevt [i].sw_nblks * 100.0);
183 }
184 }
185
186 /*
187 * If only one partition has been set up via swapon(8), we don't
188 * need to bother with totals.
189 */
190
191 if (total_partitions > 1)
192 printf ("%-10s %10d %10d %10d %7.0f%%\n", "Total",
193 total_avail / use_k,
194 (total_avail - total_free) / use_k,
195 total_free / use_k,
196 (double) (total_avail - total_free) /
197 (double) total_avail * 100.0);
198
199 exit (0);
200}