1 /* $OpenBSD: machine.c,v 1.26 2001/12/05 02:29:19 art Exp $ */ 2 3 /* 4 * top - a top users display for Unix 5 * 6 * SYNOPSIS: For an OpenBSD system 7 * 8 * DESCRIPTION: 9 * This is the machine-dependent module for OpenBSD 10 * Tested on: 11 * i386 12 * 13 * TERMCAP: -ltermlib 14 * 15 * CFLAGS: -DHAVE_GETOPT -DORDER 16 * 17 * AUTHOR: Thorsten Lockert <tholo@sigmasoft.com> 18 * Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu> 19 * Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no> 20 * Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com> 21 * Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org> 22 */ 23 24 #include <sys/types.h> 25 #include <sys/signal.h> 26 #include <sys/param.h> 27 28 #define DOSWAP 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <limits.h> 34 #include <err.h> 35 #include <math.h> 36 #include <unistd.h> 37 #include <sys/errno.h> 38 #include <sys/sysctl.h> 39 #include <sys/dir.h> 40 #include <sys/dkstat.h> 41 #include <sys/file.h> 42 #include <sys/time.h> 43 #include <sys/resource.h> 44 45 #ifdef DOSWAP 46 #include <sys/swap.h> 47 #include <err.h> 48 #endif 49 50 static int swapmode __P((int *, int *)); 51 52 #include "top.h" 53 #include "display.h" 54 #include "machine.h" 55 #include "utils.h" 56 57 /* get_process_info passes back a handle. This is what it looks like: */ 58 59 struct handle { 60 struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 61 int remaining; /* number of pointers remaining */ 62 }; 63 64 /* declarations for load_avg */ 65 #include "loadavg.h" 66 67 #define PP(pp, field) ((pp)->kp_proc . field) 68 #define EP(pp, field) ((pp)->kp_eproc . field) 69 #define VP(pp, field) ((pp)->kp_eproc.e_vm . field) 70 71 /* what we consider to be process size: */ 72 #define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize)) 73 74 /* 75 * These definitions control the format of the per-process area 76 */ 77 static char header[] = 78 " PID X PRI NICE SIZE RES STATE WAIT TIME CPU COMMAND"; 79 /* 0123456 -- field to fill in starts at header+6 */ 80 #define UNAME_START 6 81 82 #define Proc_format \ 83 "%5d %-8.8s %3d %4d %5s %5s %-5s %-6.6s %6s %5.2f%% %.14s" 84 85 86 /* process state names for the "STATE" column of the display */ 87 /* the extra nulls in the string "run" are for adding a slash and 88 the processor number when needed */ 89 90 char *state_abbrev[] = { 91 "", "start", "run\0\0\0", "sleep", "stop", "zomb", 92 }; 93 94 95 static int stathz; 96 97 /* these are for calculating cpu state percentages */ 98 static long cp_time[CPUSTATES]; 99 static long cp_old[CPUSTATES]; 100 static long cp_diff[CPUSTATES]; 101 102 /* these are for detailing the process states */ 103 int process_states[7]; 104 char *procstatenames[] = { 105 "", " starting, ", " running, ", " idle, ", " stopped, ", " zombie, ", 106 NULL 107 }; 108 109 /* these are for detailing the cpu states */ 110 int cpu_states[CPUSTATES]; 111 char *cpustatenames[] = { 112 "user", "nice", "system", "interrupt", "idle", NULL 113 }; 114 115 /* these are for detailing the memory statistics */ 116 int memory_stats[8]; 117 char *memorynames[] = { 118 "Real: ", "K/", "K act/tot ", "Free: ", "K ", 119 #ifdef DOSWAP 120 "Swap: ", "K/", "K used/tot", 121 #endif 122 NULL 123 }; 124 125 #ifdef ORDER 126 /* these are names given to allowed sorting orders -- first is default */ 127 char *ordernames[] = {"cpu", "size", "res", "time", "pri", NULL}; 128 #endif 129 130 /* these are for keeping track of the proc array */ 131 static int nproc; 132 static int onproc = -1; 133 static int pref_len; 134 static struct kinfo_proc *pbase; 135 static struct kinfo_proc **pref; 136 137 /* these are for getting the memory statistics */ 138 static int pageshift; /* log base 2 of the pagesize */ 139 140 /* define pagetok in terms of pageshift */ 141 #define pagetok(size) ((size) << pageshift) 142 143 int maxslp; 144 145 int 146 getstathz() 147 { 148 struct clockinfo cinf; 149 size_t size = sizeof(cinf); 150 int mib[2]; 151 152 mib[0] = CTL_KERN; 153 mib[1] = KERN_CLOCKRATE; 154 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 155 return (-1); 156 return (cinf.stathz); 157 } 158 159 int 160 machine_init(statics) 161 struct statics *statics; 162 { 163 int pagesize; 164 165 stathz = getstathz(); 166 if (stathz == -1) 167 return (-1); 168 169 pbase = NULL; 170 pref = NULL; 171 onproc = -1; 172 nproc = 0; 173 174 /* get the page size with "getpagesize" and calculate pageshift from 175 * it */ 176 pagesize = getpagesize(); 177 pageshift = 0; 178 while (pagesize > 1) { 179 pageshift++; 180 pagesize >>= 1; 181 } 182 183 /* we only need the amount of log(2)1024 for our conversion */ 184 pageshift -= LOG1024; 185 186 /* fill in the statics information */ 187 statics->procstate_names = procstatenames; 188 statics->cpustate_names = cpustatenames; 189 statics->memory_names = memorynames; 190 #ifdef ORDER 191 statics->order_names = ordernames; 192 #endif 193 return (0); 194 } 195 196 char * 197 format_header(uname_field) 198 char *uname_field; 199 { 200 char *ptr; 201 202 ptr = header + UNAME_START; 203 while (*uname_field != '\0') { 204 *ptr++ = *uname_field++; 205 } 206 return (header); 207 } 208 209 void 210 get_system_info(si) 211 struct system_info *si; 212 { 213 static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; 214 static int vmtotal_mib[] = {CTL_VM, VM_METER}; 215 static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; 216 struct loadavg sysload; 217 struct vmtotal vmtotal; 218 double *infoloadp; 219 int total, i; 220 size_t size; 221 222 size = sizeof(cp_time); 223 if (sysctl(cp_time_mib, 2, &cp_time, &size, NULL, 0) < 0) { 224 warn("sysctl kern.cp_time failed"); 225 total = 0; 226 } 227 228 size = sizeof(sysload); 229 if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) < 0) { 230 warn("sysctl failed"); 231 total = 0; 232 } 233 infoloadp = si->load_avg; 234 for (i = 0; i < 3; i++) 235 *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; 236 237 /* convert cp_time counts to percentages */ 238 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 239 240 /* get total -- systemwide main memory usage structure */ 241 size = sizeof(vmtotal); 242 if (sysctl(vmtotal_mib, 2, &vmtotal, &size, NULL, 0) < 0) { 243 warn("sysctl failed"); 244 bzero(&vmtotal, sizeof(vmtotal)); 245 } 246 /* convert memory stats to Kbytes */ 247 memory_stats[0] = -1; 248 memory_stats[1] = pagetok(vmtotal.t_arm); 249 memory_stats[2] = pagetok(vmtotal.t_rm); 250 memory_stats[3] = -1; 251 memory_stats[4] = pagetok(vmtotal.t_free); 252 memory_stats[5] = -1; 253 #ifdef DOSWAP 254 if (!swapmode(&memory_stats[6], &memory_stats[7])) { 255 memory_stats[6] = 0; 256 memory_stats[7] = 0; 257 } 258 #endif 259 260 /* set arrays and strings */ 261 si->cpustates = cpu_states; 262 si->memory = memory_stats; 263 si->last_pid = -1; 264 } 265 266 static struct handle handle; 267 268 struct kinfo_proc * 269 getprocs(op, arg, cnt) 270 int op, arg; 271 int *cnt; 272 { 273 size_t size = sizeof(int); 274 int mib[4] = {CTL_KERN, KERN_PROC, op, arg}; 275 int smib[2] = {CTL_KERN, KERN_NPROCS}; 276 static int maxslp_mib[] = {CTL_VM, VM_MAXSLP}; 277 static struct kinfo_proc *procbase; 278 int st; 279 280 size = sizeof(maxslp); 281 if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) < 0) { 282 warn("sysctl vm.maxslp failed"); 283 return (0); 284 } 285 286 st = sysctl(smib, 2, cnt, &size, NULL, 0); 287 if (st == -1) { 288 /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */ 289 return (0); 290 } 291 if (procbase) 292 free(procbase); 293 size = (6 * (*cnt) * sizeof(struct kinfo_proc)) / 5; 294 procbase = (struct kinfo_proc *)malloc(size); 295 if (procbase == NULL) 296 return (0); 297 st = sysctl(mib, 4, procbase, &size, NULL, 0); 298 if (st == -1) { 299 /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */ 300 return (0); 301 } 302 if (size % sizeof(struct kinfo_proc) != 0) { 303 /* _kvm_err(kd, kd->program, 304 "proc size mismatch (%d total, %d chunks)", 305 size, sizeof(struct kinfo_proc)); */ 306 return (0); 307 } 308 return (procbase); 309 } 310 311 caddr_t 312 get_process_info(si, sel, compare) 313 struct system_info *si; 314 struct process_select *sel; 315 int (*compare) __P((const void *, const void *)); 316 317 { 318 int show_idle, show_system, show_uid, show_command; 319 int total_procs, active_procs, i; 320 struct kinfo_proc **prefp, *pp; 321 322 if ((pbase = getprocs(KERN_PROC_KTHREAD, 0, &nproc)) == NULL) { 323 /* warnx("%s", kvm_geterr(kd)); */ 324 quit(23); 325 } 326 if (nproc > onproc) 327 pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) 328 * (onproc = nproc)); 329 if (pref == NULL) { 330 warnx("Out of memory."); 331 quit(23); 332 } 333 /* get a pointer to the states summary array */ 334 si->procstates = process_states; 335 336 /* set up flags which define what we are going to select */ 337 show_idle = sel->idle; 338 show_system = sel->system; 339 show_uid = sel->uid != -1; 340 show_command = sel->command != NULL; 341 342 /* count up process states and get pointers to interesting procs */ 343 total_procs = 0; 344 active_procs = 0; 345 memset((char *) process_states, 0, sizeof(process_states)); 346 prefp = pref; 347 for (pp = pbase, i = 0; i < nproc; pp++, i++) { 348 /* 349 * Place pointers to each valid proc structure in pref[]. 350 * Process slots that are actually in use have a non-zero 351 * status field. Processes with SSYS set are system 352 * processes---these get ignored unless show_sysprocs is set. 353 */ 354 if (PP(pp, p_stat) != 0 && 355 (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0))) { 356 total_procs++; 357 process_states[(unsigned char) PP(pp, p_stat)]++; 358 if ((PP(pp, p_stat) != SZOMB) && 359 (show_idle || (PP(pp, p_pctcpu) != 0) || 360 (PP(pp, p_stat) == SRUN)) && 361 (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t) sel->uid)) { 362 *prefp++ = pp; 363 active_procs++; 364 } 365 } 366 } 367 368 /* if requested, sort the "interesting" processes */ 369 if (compare != NULL) { 370 qsort((char *) pref, active_procs, sizeof(struct kinfo_proc *), compare); 371 } 372 /* remember active and total counts */ 373 si->p_total = total_procs; 374 si->p_active = pref_len = active_procs; 375 376 /* pass back a handle */ 377 handle.next_proc = pref; 378 handle.remaining = active_procs; 379 return ((caddr_t) & handle); 380 } 381 382 char fmt[MAX_COLS]; /* static area where result is built */ 383 384 char * 385 format_next_process(handle, get_userid) 386 caddr_t handle; 387 char *(*get_userid)(); 388 389 { 390 char waddr[sizeof(void *) * 2 + 3]; /* Hexify void pointer */ 391 struct kinfo_proc *pp; 392 struct handle *hp; 393 char *p_wait; 394 int cputime; 395 double pct; 396 397 /* find and remember the next proc structure */ 398 hp = (struct handle *) handle; 399 pp = *(hp->next_proc++); 400 hp->remaining--; 401 402 /* get the process's user struct and set cputime */ 403 if ((PP(pp, p_flag) & P_INMEM) == 0) { 404 /* 405 * Print swapped processes as <pname> 406 */ 407 char *comm = PP(pp, p_comm); 408 #define COMSIZ sizeof(PP(pp, p_comm)) 409 char buf[COMSIZ]; 410 (void) strncpy(buf, comm, COMSIZ); 411 comm[0] = '<'; 412 (void) strncpy(&comm[1], buf, COMSIZ - 2); 413 comm[COMSIZ - 2] = '\0'; 414 (void) strncat(comm, ">", COMSIZ - 1); 415 comm[COMSIZ - 1] = '\0'; 416 } 417 cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz; 418 419 /* calculate the base for cpu percentages */ 420 pct = pctdouble(PP(pp, p_pctcpu)); 421 422 if (PP(pp, p_wchan)) 423 if (PP(pp, p_wmesg)) 424 p_wait = EP(pp, e_wmesg); 425 else { 426 snprintf(waddr, sizeof(waddr), "%lx", 427 (unsigned long) (PP(pp, p_wchan)) & ~KERNBASE); 428 p_wait = waddr; 429 } 430 else 431 p_wait = "-"; 432 433 /* format this entry */ 434 snprintf(fmt, MAX_COLS, 435 Proc_format, 436 PP(pp, p_pid), 437 (*get_userid) (EP(pp, e_pcred.p_ruid)), 438 PP(pp, p_priority) - PZERO, 439 PP(pp, p_nice) - NZERO, 440 format_k(pagetok(PROCSIZE(pp))), 441 format_k(pagetok(VP(pp, vm_rssize))), 442 (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > maxslp) 443 ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)], 444 p_wait, 445 format_time(cputime), 446 100.0 * pct, 447 printable(PP(pp, p_comm))); 448 449 /* return the result */ 450 return (fmt); 451 } 452 453 /* comparison routine for qsort */ 454 static unsigned char sorted_state[] = 455 { 456 0, /* not used */ 457 4, /* start */ 458 5, /* run */ 459 2, /* sleep */ 460 3, /* stop */ 461 1 /* zombie */ 462 }; 463 #ifdef ORDER 464 465 /* 466 * proc_compares - comparison functions for "qsort" 467 */ 468 469 /* 470 * First, the possible comparison keys. These are defined in such a way 471 * that they can be merely listed in the source code to define the actual 472 * desired ordering. 473 */ 474 475 476 #define ORDERKEY_PCTCPU \ 477 if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \ 478 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 479 #define ORDERKEY_CPUTIME \ 480 if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \ 481 if ((result = PP(p2, p_rtime.tv_usec) - \ 482 PP(p1, p_rtime.tv_usec)) == 0) 483 #define ORDERKEY_STATE \ 484 if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \ 485 sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) 486 #define ORDERKEY_PRIO \ 487 if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0) 488 #define ORDERKEY_RSSIZE \ 489 if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0) 490 #define ORDERKEY_MEM \ 491 if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0) 492 493 494 /* compare_cpu - the comparison function for sorting by cpu percentage */ 495 int 496 compare_cpu(v1, v2) 497 const void *v1, *v2; 498 { 499 struct proc **pp1 = (struct proc **) v1; 500 struct proc **pp2 = (struct proc **) v2; 501 struct kinfo_proc *p1; 502 struct kinfo_proc *p2; 503 int result; 504 pctcpu lresult; 505 506 /* remove one level of indirection */ 507 p1 = *(struct kinfo_proc **) pp1; 508 p2 = *(struct kinfo_proc **) pp2; 509 510 ORDERKEY_PCTCPU 511 ORDERKEY_CPUTIME 512 ORDERKEY_STATE 513 ORDERKEY_PRIO 514 ORDERKEY_RSSIZE 515 ORDERKEY_MEM 516 ; 517 return (result); 518 } 519 520 /* compare_size - the comparison function for sorting by total memory usage */ 521 int 522 compare_size(v1, v2) 523 const void *v1, *v2; 524 { 525 struct proc **pp1 = (struct proc **) v1; 526 struct proc **pp2 = (struct proc **) v2; 527 struct kinfo_proc *p1; 528 struct kinfo_proc *p2; 529 int result; 530 pctcpu lresult; 531 532 /* remove one level of indirection */ 533 p1 = *(struct kinfo_proc **) pp1; 534 p2 = *(struct kinfo_proc **) pp2; 535 536 ORDERKEY_MEM 537 ORDERKEY_RSSIZE 538 ORDERKEY_PCTCPU 539 ORDERKEY_CPUTIME 540 ORDERKEY_STATE 541 ORDERKEY_PRIO 542 ; 543 return (result); 544 } 545 546 /* compare_res - the comparison function for sorting by resident set size */ 547 int 548 compare_res(v1, v2) 549 const void *v1, *v2; 550 { 551 struct proc **pp1 = (struct proc **) v1; 552 struct proc **pp2 = (struct proc **) v2; 553 struct kinfo_proc *p1; 554 struct kinfo_proc *p2; 555 int result; 556 pctcpu lresult; 557 558 /* remove one level of indirection */ 559 p1 = *(struct kinfo_proc **) pp1; 560 p2 = *(struct kinfo_proc **) pp2; 561 562 ORDERKEY_RSSIZE 563 ORDERKEY_MEM 564 ORDERKEY_PCTCPU 565 ORDERKEY_CPUTIME 566 ORDERKEY_STATE 567 ORDERKEY_PRIO 568 ; 569 return (result); 570 } 571 572 /* compare_time - the comparison function for sorting by CPU time */ 573 int 574 compare_time(v1, v2) 575 const void *v1, *v2; 576 { 577 struct proc **pp1 = (struct proc **) v1; 578 struct proc **pp2 = (struct proc **) v2; 579 struct kinfo_proc *p1; 580 struct kinfo_proc *p2; 581 int result; 582 pctcpu lresult; 583 584 /* remove one level of indirection */ 585 p1 = *(struct kinfo_proc **) pp1; 586 p2 = *(struct kinfo_proc **) pp2; 587 588 ORDERKEY_CPUTIME 589 ORDERKEY_PCTCPU 590 ORDERKEY_STATE 591 ORDERKEY_PRIO 592 ORDERKEY_MEM 593 ORDERKEY_RSSIZE 594 ; 595 return (result); 596 } 597 598 /* compare_prio - the comparison function for sorting by CPU time */ 599 int 600 compare_prio(v1, v2) 601 const void *v1, *v2; 602 { 603 struct proc **pp1 = (struct proc **) v1; 604 struct proc **pp2 = (struct proc **) v2; 605 struct kinfo_proc *p1; 606 struct kinfo_proc *p2; 607 int result; 608 pctcpu lresult; 609 610 /* remove one level of indirection */ 611 p1 = *(struct kinfo_proc **) pp1; 612 p2 = *(struct kinfo_proc **) pp2; 613 614 ORDERKEY_PRIO 615 ORDERKEY_PCTCPU 616 ORDERKEY_CPUTIME 617 ORDERKEY_STATE 618 ORDERKEY_RSSIZE 619 ORDERKEY_MEM 620 ; 621 return (result); 622 } 623 624 int (*proc_compares[]) () = { 625 compare_cpu, 626 compare_size, 627 compare_res, 628 compare_time, 629 compare_prio, 630 NULL 631 }; 632 #else 633 /* 634 * proc_compare - comparison function for "qsort" 635 * Compares the resource consumption of two processes using five 636 * distinct keys. The keys (in descending order of importance) are: 637 * percent cpu, cpu ticks, state, resident set size, total virtual 638 * memory usage. The process states are ordered as follows (from least 639 * to most important): zombie, sleep, stop, start, run. The array 640 * declaration below maps a process state index into a number that 641 * reflects this ordering. 642 */ 643 int 644 proc_compare(v1, v2) 645 const void *v1, *v2; 646 { 647 struct proc **pp1 = (struct proc **) v1; 648 struct proc **pp2 = (struct proc **) v2; 649 struct kinfo_proc *p1; 650 struct kinfo_proc *p2; 651 int result; 652 pctcpu lresult; 653 654 /* remove one level of indirection */ 655 p1 = *(struct kinfo_proc **) pp1; 656 p2 = *(struct kinfo_proc **) pp2; 657 658 /* compare percent cpu (pctcpu) */ 659 if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0) { 660 /* use CPU usage to break the tie */ 661 if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0) { 662 /* use process state to break the tie */ 663 if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - 664 sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) { 665 /* use priority to break the tie */ 666 if ((result = PP(p2, p_priority) - 667 PP(p1, p_priority)) == 0) { 668 /* use resident set size (rssize) to 669 * break the tie */ 670 if ((result = VP(p2, vm_rssize) - 671 VP(p1, vm_rssize)) == 0) { 672 /* use total memory to break 673 * the tie */ 674 result = PROCSIZE(p2) - PROCSIZE(p1); 675 } 676 } 677 } 678 } 679 } else { 680 result = lresult < 0 ? -1 : 1; 681 } 682 return (result); 683 } 684 #endif 685 686 /* 687 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 688 * the process does not exist. 689 * It is EXTREMLY IMPORTANT that this function work correctly. 690 * If top runs setuid root (as in SVR4), then this function 691 * is the only thing that stands in the way of a serious 692 * security problem. It validates requests for the "kill" 693 * and "renice" commands. 694 */ 695 int 696 proc_owner(pid) 697 pid_t pid; 698 { 699 struct kinfo_proc **prefp, *pp; 700 int cnt; 701 702 prefp = pref; 703 cnt = pref_len; 704 while (--cnt >= 0) { 705 pp = *prefp++; 706 if (PP(pp, p_pid) == pid) { 707 return ((int) EP(pp, e_pcred.p_ruid)); 708 } 709 } 710 return (-1); 711 } 712 #ifdef DOSWAP 713 /* 714 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org> 715 * to be based on the new swapctl(2) system call. 716 */ 717 static int 718 swapmode(used, total) 719 int *used; 720 int *total; 721 { 722 int nswap, rnswap, i; 723 struct swapent *swdev; 724 725 nswap = swapctl(SWAP_NSWAP, 0, 0); 726 if (nswap == 0) 727 return 0; 728 729 swdev = malloc(nswap * sizeof(*swdev)); 730 if (swdev == NULL) 731 return 0; 732 733 rnswap = swapctl(SWAP_STATS, swdev, nswap); 734 if (rnswap == -1) 735 return 0; 736 737 /* if rnswap != nswap, then what? */ 738 739 /* Total things up */ 740 *total = *used = 0; 741 for (i = 0; i < nswap; i++) { 742 if (swdev[i].se_flags & SWF_ENABLE) { 743 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE)); 744 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE)); 745 } 746 } 747 748 free(swdev); 749 return 1; 750 } 751 #endif 752