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