xref: /freebsd/lib/libkvm/kvm_getswapinfo.c (revision f0adf7f5cdd241db2f2c817683191a6ef64a4e95)
1 /*
2  * Copyright (c) 1999, Matthew Dillon.  All Rights Reserved.
3  * Copyright (c) 2001, Thomas Moestl
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided under the terms of the BSD
7  * Copyright as found in /usr/src/COPYRIGHT in the FreeBSD source tree.
8  */
9 
10 #include <sys/cdefs.h>
11 __FBSDID("$FreeBSD$");
12 
13 #include <sys/param.h>
14 #include <sys/time.h>
15 #include <sys/stat.h>
16 #include <sys/blist.h>
17 #include <sys/sysctl.h>
18 
19 #include <vm/vm_param.h>
20 
21 #include <err.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <kvm.h>
25 #include <nlist.h>
26 #include <paths.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <limits.h>
32 
33 #include "kvm_private.h"
34 
35 #define NL_SWAPBLIST	0
36 #define NL_SWDEVT	1
37 #define NL_NSWDEV	2
38 #define NL_DMMAX	3
39 
40 static int kvm_swap_nl_cached = 0;
41 static int unswdev;  /* number of found swap dev's */
42 static int dmmax;
43 
44 static int  kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int);
45 static int  getsysctl(kvm_t *, char *, void *, size_t);
46 
47 #define GETSWDEVNAME(dev, str, flags)					\
48 	if (dev == NODEV) {						\
49 		strlcpy(str, "[NFS swap]", sizeof(str));		\
50 	} else {							\
51 		snprintf(						\
52 		    str, sizeof(str),"%s%s",				\
53 		    ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""),	\
54 		    devname(dev, S_IFCHR)				\
55 		);							\
56 	}
57 
58 int
59 kvm_getswapinfo(
60 	kvm_t *kd,
61 	struct kvm_swap *swap_ary,
62 	int swap_max,
63 	int flags
64 ) {
65 
66 	/*
67 	 * clear cache
68 	 */
69 	if (kd == NULL) {
70 		kvm_swap_nl_cached = 0;
71 		return(0);
72 	}
73 
74 	if (ISALIVE(kd)) {
75 		return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags);
76 	} else {
77 		return -1;
78 	}
79 }
80 
81 #define	GETSYSCTL(kd, name, var)					\
82 	    getsysctl(kd, name, &(var), sizeof(var))
83 
84 /* The maximum MIB length for vm.swap_info and an additional device number */
85 #define	SWI_MAXMIB	3
86 
87 int
88 kvm_getswapinfo_sysctl(
89 	kvm_t *kd,
90 	struct kvm_swap *swap_ary,
91 	int swap_max,
92 	int flags
93 ) {
94 	int ti, ttl;
95 	size_t mibi, len;
96 	int soid[SWI_MAXMIB];
97 	struct xswdev xsd;
98 	struct kvm_swap tot;
99 
100 	if (!GETSYSCTL(kd, "vm.dmmax", dmmax))
101 		return -1;
102 
103 	mibi = SWI_MAXMIB - 1;
104 	if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
105 		_kvm_err(kd, kd->program, "sysctlnametomib failed: %s",
106 		    strerror(errno));
107 		return -1;
108 	}
109 	bzero(&tot, sizeof(tot));
110 	for (unswdev = 0;; unswdev++) {
111 		soid[mibi] = unswdev;
112 		len = sizeof(xsd);
113 		if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
114 			if (errno == ENOENT)
115 				break;
116 			_kvm_err(kd, kd->program, "cannot read sysctl: %s.",
117 			    strerror(errno));
118 			return -1;
119 		}
120 		if (len != sizeof(xsd)) {
121 			_kvm_err(kd, kd->program, "struct xswdev has unexpected "
122 			    "size;  kernel and libkvm out of sync?");
123 			return -1;
124 		}
125 		if (xsd.xsw_version != XSWDEV_VERSION) {
126 			_kvm_err(kd, kd->program, "struct xswdev version "
127 			    "mismatch; kernel and libkvm out of sync?");
128 			return -1;
129 		}
130 
131 		ttl = xsd.xsw_nblks - dmmax;
132 		if (unswdev < swap_max - 1) {
133 			bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
134 			swap_ary[unswdev].ksw_total = ttl;
135 			swap_ary[unswdev].ksw_used = xsd.xsw_used;
136 			swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
137 			GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname,
138 			     flags);
139 		}
140 		tot.ksw_total += ttl;
141 		tot.ksw_used += xsd.xsw_used;
142 	}
143 
144 	ti = unswdev;
145 	if (ti >= swap_max)
146 		ti = swap_max - 1;
147 	if (ti >= 0)
148 		swap_ary[ti] = tot;
149 
150         return(ti);
151 }
152 
153 static int
154 getsysctl (
155 	kvm_t *kd,
156 	char *name,
157 	void *ptr,
158 	size_t len
159 ) {
160 	size_t nlen = len;
161 	if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
162 		_kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name,
163 		    strerror(errno));
164 		return (0);
165 	}
166 	if (nlen != len) {
167 		_kvm_err(kd, kd->program, "sysctl %s has unexpected size", name);
168 		return (0);
169 	}
170 	return (1);
171 }
172