1 /* $OpenBSD: pool.c,v 1.10 2015/01/16 00:03:37 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/signal.h> 20 #include <sys/sysctl.h> 21 #include <sys/pool.h> 22 #include <errno.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <limits.h> 26 27 #include "systat.h" 28 29 void print_pool(void); 30 int read_pool(void); 31 void sort_pool(void); 32 int select_pool(void); 33 void showpool(int k); 34 int pool_keyboard_callback(int); 35 36 /* qsort callbacks */ 37 int sort_name_callback(const void *s1, const void *s2); 38 int sort_req_callback(const void *s1, const void *s2); 39 int sort_psize_callback(const void *s1, const void *s2); 40 int sort_npage_callback(const void *s1, const void *s2); 41 42 struct pool_info { 43 char name[32]; 44 struct kinfo_pool pool; 45 }; 46 47 48 int print_all = 0; 49 int num_pools = 0; 50 struct pool_info *pools = NULL; 51 52 53 field_def fields_pool[] = { 54 {"NAME", 11, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 55 {"SIZE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 56 {"REQUESTS", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 57 {"FAIL", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 58 {"INUSE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 59 {"PGREQ", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 60 {"PGREL", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 61 {"NPAGE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 62 {"HIWAT", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 63 {"MINPG", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 64 {"MAXPG", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"IDLE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0} 66 }; 67 68 69 #define FLD_POOL_NAME FIELD_ADDR(fields_pool,0) 70 #define FLD_POOL_SIZE FIELD_ADDR(fields_pool,1) 71 #define FLD_POOL_REQS FIELD_ADDR(fields_pool,2) 72 #define FLD_POOL_FAIL FIELD_ADDR(fields_pool,3) 73 #define FLD_POOL_INUSE FIELD_ADDR(fields_pool,4) 74 #define FLD_POOL_PGREQ FIELD_ADDR(fields_pool,5) 75 #define FLD_POOL_PGREL FIELD_ADDR(fields_pool,6) 76 #define FLD_POOL_NPAGE FIELD_ADDR(fields_pool,7) 77 #define FLD_POOL_HIWAT FIELD_ADDR(fields_pool,8) 78 #define FLD_POOL_MINPG FIELD_ADDR(fields_pool,9) 79 #define FLD_POOL_MAXPG FIELD_ADDR(fields_pool,10) 80 #define FLD_POOL_IDLE FIELD_ADDR(fields_pool,11) 81 82 /* Define views */ 83 field_def *view_pool_0[] = { 84 FLD_POOL_NAME, FLD_POOL_SIZE, FLD_POOL_REQS, FLD_POOL_FAIL, 85 FLD_POOL_INUSE, FLD_POOL_PGREQ, FLD_POOL_PGREL, FLD_POOL_NPAGE, 86 FLD_POOL_HIWAT, FLD_POOL_MINPG, FLD_POOL_MAXPG, FLD_POOL_IDLE, NULL 87 }; 88 89 order_type pool_order_list[] = { 90 {"name", "name", 'N', sort_name_callback}, 91 {"requests", "requests", 'Q', sort_req_callback}, 92 {"size", "size", 'Z', sort_psize_callback}, 93 {"npages", "npages", 'P', sort_npage_callback}, 94 {NULL, NULL, 0, NULL} 95 }; 96 97 /* Define view managers */ 98 struct view_manager pool_mgr = { 99 "Pool", select_pool, read_pool, sort_pool, print_header, 100 print_pool, pool_keyboard_callback, pool_order_list, pool_order_list 101 }; 102 103 field_view views_pool[] = { 104 {view_pool_0, "pool", '5', &pool_mgr}, 105 {NULL, NULL, 0, NULL} 106 }; 107 108 109 int 110 sort_name_callback(const void *s1, const void *s2) 111 { 112 struct pool_info *p1, *p2; 113 p1 = (struct pool_info *)s1; 114 p2 = (struct pool_info *)s2; 115 116 return strcmp(p1->name, p2->name) * sortdir; 117 } 118 119 int 120 sort_req_callback(const void *s1, const void *s2) 121 { 122 struct pool_info *p1, *p2; 123 p1 = (struct pool_info *)s1; 124 p2 = (struct pool_info *)s2; 125 126 if (p1->pool.pr_nget < p2->pool.pr_nget) 127 return sortdir; 128 if (p1->pool.pr_nget > p2->pool.pr_nget) 129 return -sortdir; 130 131 return sort_name_callback(s1, s2); 132 } 133 134 int 135 sort_npage_callback(const void *s1, const void *s2) 136 { 137 struct pool_info *p1, *p2; 138 p1 = (struct pool_info *)s1; 139 p2 = (struct pool_info *)s2; 140 141 if (p1->pool.pr_npages < p2->pool.pr_npages) 142 return sortdir; 143 if (p1->pool.pr_npages > p2->pool.pr_npages) 144 return -sortdir; 145 146 return sort_name_callback(s1, s2); 147 } 148 149 int 150 sort_psize_callback(const void *s1, const void *s2) 151 { 152 struct pool_info *p1, *p2; 153 size_t ps1, ps2; 154 155 p1 = (struct pool_info *)s1; 156 p2 = (struct pool_info *)s2; 157 158 ps1 = (size_t)(p1->pool.pr_nget - p1->pool.pr_nput) * 159 (size_t)p1->pool.pr_size; 160 ps2 = (size_t)(p2->pool.pr_nget - p2->pool.pr_nput) * 161 (size_t)p2->pool.pr_size; 162 163 if (ps1 < ps2) 164 return sortdir; 165 if (ps1 > ps2) 166 return -sortdir; 167 168 return sort_npage_callback(s1, s2); 169 } 170 171 void 172 sort_pool(void) 173 { 174 order_type *ordering; 175 176 if (curr_mgr == NULL) 177 return; 178 179 ordering = curr_mgr->order_curr; 180 181 if (ordering == NULL) 182 return; 183 if (ordering->func == NULL) 184 return; 185 if (pools == NULL) 186 return; 187 if (num_pools <= 0) 188 return; 189 190 mergesort(pools, num_pools, sizeof(struct pool_info), ordering->func); 191 } 192 193 int 194 select_pool(void) 195 { 196 num_disp = num_pools; 197 return (0); 198 } 199 200 int 201 read_pool(void) 202 { 203 int mib[4], np, i; 204 size_t size; 205 206 mib[0] = CTL_KERN; 207 mib[1] = KERN_POOL; 208 mib[2] = KERN_POOL_NPOOLS; 209 size = sizeof(np); 210 211 if (sysctl(mib, 3, &np, &size, NULL, 0) < 0) { 212 error("sysctl(npools): %s", strerror(errno)); 213 return (-1); 214 } 215 216 if (np <= 0) { 217 num_pools = 0; 218 return (0); 219 } 220 221 if (np > num_pools || pools == NULL) { 222 struct pool_info *p = reallocarray(pools, np, sizeof(*pools)); 223 if (p == NULL) { 224 error("realloc: %s", strerror(errno)); 225 return (-1); 226 } 227 pools = p; 228 num_pools = np; 229 } 230 231 num_disp = num_pools; 232 233 for (i = 0; i < num_pools; i++) { 234 mib[0] = CTL_KERN; 235 mib[1] = KERN_POOL; 236 mib[2] = KERN_POOL_POOL; 237 mib[3] = i + 1; 238 size = sizeof(pools[i].pool); 239 if (sysctl(mib, 4, &pools[i].pool, &size, NULL, 0) < 0) { 240 memset(&pools[i], 0, sizeof(pools[i])); 241 num_disp--; 242 continue; 243 } 244 mib[2] = KERN_POOL_NAME; 245 size = sizeof(pools[i].name); 246 if (sysctl(mib, 4, &pools[i].name, &size, NULL, 0) < 0) { 247 snprintf(pools[i].name, size, "#%d#", mib[3]); 248 } 249 } 250 251 if (i != num_pools) { 252 memset(pools, 0, sizeof(*pools) * num_pools); 253 return (-1); 254 } 255 256 return 0; 257 } 258 259 260 void 261 print_pool(void) 262 { 263 struct pool_info *p; 264 int i, n, count = 0; 265 266 if (pools == NULL) 267 return; 268 269 for (n = i = 0; i < num_pools; i++) { 270 p = &pools[i]; 271 if (p->name[0] == 0) 272 continue; 273 274 if (!print_all && 275 (p->pool.pr_nget == 0 && p->pool.pr_npagealloc == 0)) 276 continue; 277 278 if (n++ < dispstart) 279 continue; 280 showpool(i); 281 count++; 282 if (maxprint > 0 && count >= maxprint) 283 break; 284 } 285 } 286 287 int 288 initpool(void) 289 { 290 field_view *v; 291 292 for (v = views_pool; v->name != NULL; v++) 293 add_view(v); 294 295 read_pool(); 296 297 return(0); 298 } 299 300 void 301 showpool(int k) 302 { 303 struct pool_info *p = pools + k; 304 305 if (k < 0 || k >= num_pools) 306 return; 307 308 print_fld_str(FLD_POOL_NAME, p->name); 309 print_fld_uint(FLD_POOL_SIZE, p->pool.pr_size); 310 311 print_fld_size(FLD_POOL_REQS, p->pool.pr_nget); 312 print_fld_size(FLD_POOL_FAIL, p->pool.pr_nfail); 313 print_fld_ssize(FLD_POOL_INUSE, p->pool.pr_nget - p->pool.pr_nput); 314 print_fld_size(FLD_POOL_PGREQ, p->pool.pr_npagealloc); 315 print_fld_size(FLD_POOL_PGREL, p->pool.pr_npagefree); 316 317 print_fld_size(FLD_POOL_NPAGE, p->pool.pr_npages); 318 print_fld_size(FLD_POOL_HIWAT, p->pool.pr_hiwat); 319 print_fld_size(FLD_POOL_MINPG, p->pool.pr_minpages); 320 321 if (p->pool.pr_maxpages == UINT_MAX) 322 print_fld_str(FLD_POOL_MAXPG, "inf"); 323 else 324 print_fld_size(FLD_POOL_MAXPG, p->pool.pr_maxpages); 325 326 print_fld_size(FLD_POOL_IDLE, p->pool.pr_nidle); 327 328 end_line(); 329 } 330 331 int 332 pool_keyboard_callback(int ch) 333 { 334 switch (ch) { 335 case 'A': 336 print_all ^= 1; 337 gotsig_alarm = 1; 338 default: 339 return keyboard_callback(ch); 340 }; 341 342 return (1); 343 } 344