1 /* $NetBSD: print.c,v 1.72 2002/04/24 21:41:22 nathanw Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Simon Burge. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1990, 1993, 1994 41 * The Regents of the University of California. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 */ 71 72 #include <sys/cdefs.h> 73 #ifndef lint 74 #if 0 75 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; 76 #else 77 __RCSID("$NetBSD: print.c,v 1.72 2002/04/24 21:41:22 nathanw Exp $"); 78 #endif 79 #endif /* not lint */ 80 81 #include <sys/param.h> 82 #include <sys/time.h> 83 #include <sys/resource.h> 84 #include <sys/proc.h> 85 #include <sys/stat.h> 86 #include <sys/ucred.h> 87 #include <sys/sysctl.h> 88 89 #include <err.h> 90 #include <kvm.h> 91 #include <math.h> 92 #include <nlist.h> 93 #include <pwd.h> 94 #include <stddef.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <string.h> 98 #include <time.h> 99 #include <tzfile.h> 100 #include <unistd.h> 101 102 #include "ps.h" 103 104 static char *cmdpart __P((char *)); 105 static void printval __P((void *, VAR *, int)); 106 static int titlecmp __P((char *, char **)); 107 108 static void doubleprintorsetwidth __P((VAR *, double, int, int)); 109 static void intprintorsetwidth __P((VAR *, int, int)); 110 static void strprintorsetwidth __P((VAR *, const char *, int)); 111 112 #define min(a,b) ((a) <= (b) ? (a) : (b)) 113 #define max(a,b) ((a) >= (b) ? (a) : (b)) 114 115 static char * 116 cmdpart(arg0) 117 char *arg0; 118 { 119 char *cp; 120 121 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 122 } 123 124 void 125 printheader() 126 { 127 int len; 128 VAR *v; 129 struct varent *vent; 130 static int firsttime = 1; 131 132 for (vent = vhead; vent; vent = vent->next) { 133 v = vent->var; 134 if (firsttime) { 135 len = strlen(v->header); 136 if (len > v->width) 137 v->width = len; 138 totwidth += v->width + 1; /* +1 for space */ 139 } 140 if (v->flag & LJUST) { 141 if (vent->next == NULL) /* last one */ 142 (void)printf("%s", v->header); 143 else 144 (void)printf("%-*s", v->width, 145 v->header); 146 } else 147 (void)printf("%*s", v->width, v->header); 148 if (vent->next != NULL) 149 (void)putchar(' '); 150 } 151 (void)putchar('\n'); 152 if (firsttime) { 153 firsttime = 0; 154 totwidth--; /* take off last space */ 155 } 156 } 157 158 /* 159 * Return 1 if the the command name in the argument vector (u-area) does 160 * not match the command name (p_comm) 161 */ 162 static int 163 titlecmp(name, argv) 164 char *name; 165 char **argv; 166 { 167 char *title; 168 int namelen; 169 170 171 /* no argument vector == no match; system processes/threads do that */ 172 if (argv == 0 || argv[0] == 0) 173 return (1); 174 175 title = cmdpart(argv[0]); 176 177 /* the basename matches */ 178 if (!strcmp(name, title)) 179 return (0); 180 181 /* handle login shells, by skipping the leading - */ 182 if (title[0] == '-' && !strcmp(name, title+1)) 183 return (0); 184 185 namelen = strlen(name); 186 187 /* handle daemons that report activity as daemonname: activity */ 188 if (argv[1] == 0 && 189 !strncmp(name, title, namelen) && 190 title[namelen + 0] == ':' && 191 title[namelen + 1] == ' ') 192 return (0); 193 194 return (1); 195 } 196 197 static void 198 doubleprintorsetwidth(v, val, prec, mode) 199 VAR *v; 200 double val; 201 int prec; 202 int mode; 203 { 204 int fmtlen; 205 206 if (mode == WIDTHMODE) { 207 if (val < 0.0 && val < v->longestnd) { 208 fmtlen = (int)log10(-val) + prec + 2; 209 v->longestnd = val; 210 if (fmtlen > v->width) 211 v->width = fmtlen; 212 } else if (val > 0.0 && val > v->longestpd) { 213 fmtlen = (int)log10(val) + prec + 1; 214 v->longestpd = val; 215 if (fmtlen > v->width) 216 v->width = fmtlen; 217 } 218 } else { 219 printf("%*.*f", v->width, prec, val); 220 } 221 } 222 223 static void 224 intprintorsetwidth(v, val, mode) 225 VAR *v; 226 int val; 227 int mode; 228 { 229 int fmtlen; 230 231 if (mode == WIDTHMODE) { 232 if (val < 0 && val < v->longestn) { 233 fmtlen = (int)log10((double)-val) + 2; 234 v->longestn = val; 235 if (fmtlen > v->width) 236 v->width = fmtlen; 237 } else if (val > 0 && val > v->longestp) { 238 fmtlen = (int)log10((double)val) + 1; 239 v->longestp = val; 240 if (fmtlen > v->width) 241 v->width = fmtlen; 242 } 243 } else 244 printf("%*d", v->width, val); 245 } 246 247 static void 248 strprintorsetwidth(v, str, mode) 249 VAR *v; 250 const char *str; 251 { 252 int len; 253 254 if (mode == WIDTHMODE) { 255 len = strlen(str); 256 if (len > v->width) 257 v->width = len; 258 } else { 259 if (v->flag & LJUST) 260 printf("%-*.*s", v->width, v->width, str); 261 else 262 printf("%*.*s", v->width, v->width, str); 263 } 264 } 265 266 void 267 command(ki, ve, mode) 268 struct kinfo_proc2 *ki; 269 VARENT *ve; 270 int mode; 271 { 272 VAR *v; 273 int left; 274 char **argv, **p, *name; 275 276 if (mode == WIDTHMODE) 277 return; 278 279 v = ve->var; 280 if (ve->next != NULL || termwidth != UNLIMITED) { 281 if (ve->next == NULL) { 282 left = termwidth - (totwidth - v->width); 283 if (left < 1) /* already wrapped, just use std width */ 284 left = v->width; 285 } else 286 left = v->width; 287 } else 288 left = -1; 289 if (needenv && kd) { 290 argv = kvm_getenvv2(kd, ki, termwidth); 291 if ((p = argv) != NULL) { 292 while (*p) { 293 fmt_puts(*p, &left); 294 p++; 295 fmt_putc(' ', &left); 296 } 297 } 298 } 299 if (needcomm) { 300 name = ki->p_comm; 301 if (!commandonly) { 302 argv = NULL; 303 if (!use_procfs) 304 argv = kvm_getargv2(kd, ki, termwidth); 305 else 306 argv = procfs_getargv(ki, termwidth); 307 if ((p = argv) != NULL) { 308 while (*p) { 309 fmt_puts(*p, &left); 310 p++; 311 fmt_putc(' ', &left); 312 } 313 if (titlecmp(name, argv)) { 314 /* 315 * append the real command name within 316 * parentheses, if the command name 317 * does not match the one in the 318 * argument vector 319 */ 320 fmt_putc('(', &left); 321 fmt_puts(name, &left); 322 fmt_putc(')', &left); 323 } 324 if (use_procfs) { 325 free(argv[0]); 326 free(argv); 327 } 328 } else { 329 /* 330 * Commands that don't set an argv vector 331 * are printed with square brackets if they 332 * are system commands. Otherwise they are 333 * printed within parentheses. 334 */ 335 if (ki->p_flag & P_SYSTEM) { 336 fmt_putc('[', &left); 337 fmt_puts(name, &left); 338 fmt_putc(']', &left); 339 } else { 340 fmt_putc('(', &left); 341 fmt_puts(name, &left); 342 fmt_putc(')', &left); 343 } 344 } 345 } else { 346 fmt_puts(name, &left); 347 } 348 } 349 if (ve->next && left > 0) 350 printf("%*s", left, ""); 351 } 352 353 void 354 ucomm(k, ve, mode) 355 struct kinfo_proc2 *k; 356 VARENT *ve; 357 int mode; 358 { 359 VAR *v; 360 361 v = ve->var; 362 strprintorsetwidth(v, k->p_comm, mode); 363 } 364 365 void 366 logname(k, ve, mode) 367 struct kinfo_proc2 *k; 368 VARENT *ve; 369 int mode; 370 { 371 VAR *v; 372 373 v = ve->var; 374 strprintorsetwidth(v, k->p_login, mode); 375 } 376 377 void 378 state(k, ve, mode) 379 struct kinfo_proc2 *k; 380 VARENT *ve; 381 int mode; 382 { 383 int flag, is_zombie; 384 char *cp; 385 VAR *v; 386 char buf[16]; 387 388 is_zombie = 0; 389 v = ve->var; 390 flag = k->p_flag; 391 cp = buf; 392 393 switch (k->p_stat) { 394 395 case SSTOP: 396 *cp = 'T'; 397 break; 398 399 case SSLEEP: 400 if (flag & P_SINTR) /* interuptable (long) */ 401 *cp = k->p_slptime >= maxslp ? 'I' : 'S'; 402 else 403 *cp = 'D'; 404 break; 405 406 case SRUN: 407 case SIDL: 408 case SONPROC: 409 *cp = 'R'; 410 break; 411 412 case SZOMB: 413 case SDEAD: 414 *cp = 'Z'; 415 is_zombie = 1; 416 break; 417 418 default: 419 *cp = '?'; 420 } 421 cp++; 422 if (flag & P_INMEM) { 423 } else 424 *cp++ = 'W'; 425 if (k->p_nice < NZERO) 426 *cp++ = '<'; 427 else if (k->p_nice > NZERO) 428 *cp++ = 'N'; 429 if (flag & P_TRACED) 430 *cp++ = 'X'; 431 if (flag & P_WEXIT && !is_zombie) 432 *cp++ = 'E'; 433 if (flag & P_PPWAIT) 434 *cp++ = 'V'; 435 if (flag & P_SYSTEM) 436 *cp++ = 'K'; 437 /* system process might have this too, don't need to double up */ 438 else if (k->p_holdcnt) 439 *cp++ = 'L'; 440 if (k->p_eflag & EPROC_SLEADER) 441 *cp++ = 's'; 442 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid) 443 *cp++ = '+'; 444 *cp = '\0'; 445 strprintorsetwidth(v, buf, mode); 446 } 447 448 void 449 pnice(k, ve, mode) 450 struct kinfo_proc2 *k; 451 VARENT *ve; 452 int mode; 453 { 454 VAR *v; 455 456 v = ve->var; 457 intprintorsetwidth(v, k->p_nice - NZERO, mode); 458 } 459 460 void 461 pri(k, ve, mode) 462 struct kinfo_proc2 *k; 463 VARENT *ve; 464 int mode; 465 { 466 VAR *v; 467 468 v = ve->var; 469 intprintorsetwidth(v, k->p_priority - PZERO, mode); 470 } 471 472 void 473 uname(k, ve, mode) 474 struct kinfo_proc2 *k; 475 VARENT *ve; 476 int mode; 477 { 478 VAR *v; 479 480 v = ve->var; 481 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode); 482 } 483 484 void 485 runame(k, ve, mode) 486 struct kinfo_proc2 *k; 487 VARENT *ve; 488 int mode; 489 { 490 VAR *v; 491 492 v = ve->var; 493 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode); 494 } 495 496 void 497 tdev(k, ve, mode) 498 struct kinfo_proc2 *k; 499 VARENT *ve; 500 int mode; 501 { 502 VAR *v; 503 dev_t dev; 504 char buff[16]; 505 506 v = ve->var; 507 dev = k->p_tdev; 508 if (dev == NODEV) { 509 /* 510 * Minimum width is width of header - we don't 511 * need to check it every time. 512 */ 513 if (mode == PRINTMODE) 514 (void)printf("%*s", v->width, "??"); 515 } else { 516 (void)snprintf(buff, sizeof(buff), 517 "%d/%d", major(dev), minor(dev)); 518 strprintorsetwidth(v, buff, mode); 519 } 520 } 521 522 void 523 tname(k, ve, mode) 524 struct kinfo_proc2 *k; 525 VARENT *ve; 526 int mode; 527 { 528 VAR *v; 529 dev_t dev; 530 const char *ttname; 531 int noctty; 532 533 v = ve->var; 534 dev = k->p_tdev; 535 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 536 /* 537 * Minimum width is width of header - we don't 538 * need to check it every time. 539 */ 540 if (mode == PRINTMODE) 541 (void)printf("%-*s", v->width, "??"); 542 } else { 543 if (strncmp(ttname, "tty", 3) == 0 || 544 strncmp(ttname, "dty", 3) == 0) 545 ttname += 3; 546 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0; 547 if (mode == WIDTHMODE) { 548 int fmtlen; 549 550 fmtlen = strlen(ttname) + noctty; 551 if (v->width < fmtlen) 552 v->width = fmtlen; 553 } else { 554 if (noctty) 555 printf("%-*s-", v->width - 1, ttname); 556 else 557 printf("%-*s", v->width, ttname); 558 } 559 } 560 } 561 562 void 563 longtname(k, ve, mode) 564 struct kinfo_proc2 *k; 565 VARENT *ve; 566 int mode; 567 { 568 VAR *v; 569 dev_t dev; 570 const char *ttname; 571 572 v = ve->var; 573 dev = k->p_tdev; 574 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 575 /* 576 * Minimum width is width of header - we don't 577 * need to check it every time. 578 */ 579 if (mode == PRINTMODE) 580 (void)printf("%-*s", v->width, "??"); 581 } 582 else { 583 strprintorsetwidth(v, ttname, mode); 584 } 585 } 586 587 void 588 started(k, ve, mode) 589 struct kinfo_proc2 *k; 590 VARENT *ve; 591 int mode; 592 { 593 VAR *v; 594 static time_t now; 595 time_t startt; 596 struct tm *tp; 597 char buf[100], *cp; 598 599 v = ve->var; 600 if (!k->p_uvalid) { 601 if (mode == PRINTMODE) 602 (void)printf("%*s", v->width, "-"); 603 return; 604 } 605 606 startt = k->p_ustart_sec; 607 tp = localtime(&startt); 608 if (!now) 609 (void)time(&now); 610 if (now - k->p_ustart_sec < SECSPERDAY) 611 /* I *hate* SCCS... */ 612 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 613 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 614 /* I *hate* SCCS... */ 615 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 616 else 617 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 618 /* %e and %l can start with a space. */ 619 cp = buf; 620 if (*cp == ' ') 621 cp++; 622 strprintorsetwidth(v, cp, mode); 623 } 624 625 void 626 lstarted(k, ve, mode) 627 struct kinfo_proc2 *k; 628 VARENT *ve; 629 int mode; 630 { 631 VAR *v; 632 time_t startt; 633 char buf[100]; 634 635 v = ve->var; 636 if (!k->p_uvalid) { 637 /* 638 * Minimum width is less than header - we don't 639 * need to check it every time. 640 */ 641 if (mode == PRINTMODE) 642 (void)printf("%*s", v->width, "-"); 643 return; 644 } 645 startt = k->p_ustart_sec; 646 647 /* assume all times are the same length */ 648 if (mode != WIDTHMODE || v->width == 0) { 649 (void)strftime(buf, sizeof(buf) -1, "%c", 650 localtime(&startt)); 651 strprintorsetwidth(v, buf, mode); 652 } 653 } 654 655 void 656 wchan(k, ve, mode) 657 struct kinfo_proc2 *k; 658 VARENT *ve; 659 int mode; 660 { 661 VAR *v; 662 char *buf; 663 664 v = ve->var; 665 if (k->p_wchan) { 666 if (k->p_wmesg) { 667 strprintorsetwidth(v, k->p_wmesg, mode); 668 v->width = min(v->width, WMESGLEN); 669 } else { 670 (void)asprintf(&buf, "%-*llx", v->width, 671 (long long)k->p_wchan); 672 if (buf == NULL) 673 err(1, "%s", ""); 674 strprintorsetwidth(v, buf, mode); 675 v->width = min(v->width, WMESGLEN); 676 free(buf); 677 } 678 } else { 679 if (mode == PRINTMODE) 680 (void)printf("%-*s", v->width, "-"); 681 } 682 } 683 684 #define pgtok(a) (((a)*getpagesize())/1024) 685 686 void 687 vsize(k, ve, mode) 688 struct kinfo_proc2 *k; 689 VARENT *ve; 690 int mode; 691 { 692 VAR *v; 693 694 v = ve->var; 695 intprintorsetwidth(v, 696 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode); 697 } 698 699 void 700 rssize(k, ve, mode) 701 struct kinfo_proc2 *k; 702 VARENT *ve; 703 int mode; 704 { 705 VAR *v; 706 707 v = ve->var; 708 /* XXX don't have info about shared */ 709 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 710 } 711 712 void 713 p_rssize(k, ve, mode) /* doesn't account for text */ 714 struct kinfo_proc2 *k; 715 VARENT *ve; 716 int mode; 717 { 718 VAR *v; 719 720 v = ve->var; 721 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 722 } 723 724 void 725 cputime(k, ve, mode) 726 struct kinfo_proc2 *k; 727 VARENT *ve; 728 int mode; 729 { 730 VAR *v; 731 int32_t secs; 732 int32_t psecs; /* "parts" of a second. first micro, then centi */ 733 int fmtlen; 734 735 v = ve->var; 736 if (P_ZOMBIE(k) || k->p_uvalid == 0) { 737 secs = 0; 738 psecs = 0; 739 } else { 740 /* 741 * This counts time spent handling interrupts. We could 742 * fix this, but it is not 100% trivial (and interrupt 743 * time fractions only work on the sparc anyway). XXX 744 */ 745 secs = k->p_rtime_sec; 746 psecs = k->p_rtime_usec; 747 if (sumrusage) { 748 secs += k->p_uctime_sec; 749 psecs += k->p_uctime_usec; 750 } 751 /* 752 * round and scale to 100's 753 */ 754 psecs = (psecs + 5000) / 10000; 755 secs += psecs / 100; 756 psecs = psecs % 100; 757 } 758 if (mode == WIDTHMODE) { 759 /* 760 * Ugg, this is the only field where a value of 0 longer 761 * than the column title, and log10(0) isn't good enough. 762 * Use SECSPERMIN, because secs is divided by that when 763 * passed to log10(). 764 */ 765 if (secs == 0 && v->longestp == 0) 766 secs = SECSPERMIN; 767 if (secs > v->longestp) { 768 /* "+6" for the "%02ld.%02ld" in the printf() below */ 769 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6; 770 v->longestp = secs; 771 if (fmtlen > v->width) 772 v->width = fmtlen; 773 } 774 } else { 775 printf("%*ld:%02ld.%02ld", v->width - 6, (long)(secs / SECSPERMIN), 776 (long)(secs % SECSPERMIN), (long)psecs); 777 } 778 } 779 780 double 781 getpcpu(k) 782 struct kinfo_proc2 *k; 783 { 784 static int failure; 785 786 if (!nlistread) 787 failure = (kd) ? donlist() : 1; 788 if (failure) 789 return (0.0); 790 791 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 792 793 /* XXX - I don't like this */ 794 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 || 795 k->p_stat == SZOMB || k->p_stat == SDEAD) 796 return (0.0); 797 if (rawcpu) 798 return (100.0 * fxtofl(k->p_pctcpu)); 799 return (100.0 * fxtofl(k->p_pctcpu) / 800 (1.0 - exp(k->p_swtime * log(ccpu)))); 801 } 802 803 void 804 pcpu(k, ve, mode) 805 struct kinfo_proc2 *k; 806 VARENT *ve; 807 int mode; 808 { 809 VAR *v; 810 811 v = ve->var; 812 doubleprintorsetwidth(v, getpcpu(k), 1, mode); 813 } 814 815 double 816 getpmem(k) 817 struct kinfo_proc2 *k; 818 { 819 static int failure; 820 double fracmem; 821 int szptudot; 822 823 if (!nlistread) 824 failure = (kd) ? donlist() : 1; 825 if (failure) 826 return (0.0); 827 828 if ((k->p_flag & P_INMEM) == 0) 829 return (0.0); 830 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 831 szptudot = uspace/getpagesize(); 832 /* XXX don't have info about shared */ 833 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 834 return (100.0 * fracmem); 835 } 836 837 void 838 pmem(k, ve, mode) 839 struct kinfo_proc2 *k; 840 VARENT *ve; 841 int mode; 842 { 843 VAR *v; 844 845 v = ve->var; 846 doubleprintorsetwidth(v, getpmem(k), 1, mode); 847 } 848 849 void 850 pagein(k, ve, mode) 851 struct kinfo_proc2 *k; 852 VARENT *ve; 853 int mode; 854 { 855 VAR *v; 856 857 v = ve->var; 858 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 859 } 860 861 void 862 maxrss(k, ve, mode) 863 struct kinfo_proc2 *k; 864 VARENT *ve; 865 int mode; 866 { 867 VAR *v; 868 869 v = ve->var; 870 /* No need to check width! */ 871 if (mode == PRINTMODE) 872 (void)printf("%*s", v->width, "-"); 873 } 874 875 void 876 tsize(k, ve, mode) 877 struct kinfo_proc2 *k; 878 VARENT *ve; 879 int mode; 880 { 881 VAR *v; 882 883 v = ve->var; 884 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 885 } 886 887 /* 888 * Generic output routines. Print fields from various prototype 889 * structures. 890 */ 891 static void 892 printval(bp, v, mode) 893 void *bp; 894 VAR *v; 895 int mode; 896 { 897 static char ofmt[32] = "%"; 898 int width, vok, fmtlen; 899 char *fcp, *cp, *obuf; 900 enum type type; 901 long long val; 902 unsigned long long uval; 903 904 /* 905 * Note that the "INF127" check is nonsensical for types 906 * that are or can be signed. 907 */ 908 #define GET(type) (*(type *)bp) 909 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 910 911 #define VSIGN 1 912 #define VUNSIGN 2 913 #define VPTR 3 914 915 if (mode == WIDTHMODE) { 916 vok = 0; 917 switch (v->type) { 918 case CHAR: 919 val = GET(char); 920 vok = VSIGN; 921 break; 922 case UCHAR: 923 uval = CHK_INF127(GET(u_char)); 924 vok = VUNSIGN; 925 break; 926 case SHORT: 927 val = GET(short); 928 vok = VSIGN; 929 break; 930 case USHORT: 931 uval = CHK_INF127(GET(u_short)); 932 vok = VUNSIGN; 933 break; 934 case INT32: 935 val = GET(int32_t); 936 vok = VSIGN; 937 break; 938 case INT: 939 val = GET(int); 940 vok = VSIGN; 941 break; 942 case UINT: 943 case UINT32: 944 uval = CHK_INF127(GET(u_int)); 945 vok = VUNSIGN; 946 break; 947 case LONG: 948 val = GET(long); 949 vok = VSIGN; 950 break; 951 case ULONG: 952 uval = CHK_INF127(GET(u_long)); 953 vok = VUNSIGN; 954 break; 955 case KPTR: 956 uval = (unsigned long long)GET(u_int64_t); 957 vok = VPTR; 958 break; 959 case KPTR24: 960 uval = (unsigned long long)GET(u_int64_t); 961 uval &= 0xffffff; 962 vok = VPTR; 963 break; 964 case INT64: 965 val = (long long)GET(int64_t); 966 vok = VSIGN; 967 break; 968 case UINT64: 969 uval = (unsigned long long)CHK_INF127(GET(u_int64_t)); 970 vok = VUNSIGN; 971 break; 972 973 default: 974 /* nothing... */; 975 } 976 switch (vok) { 977 case VSIGN: 978 if (val < 0 && val < v->longestn) { 979 fmtlen = (int)log10((double)-val) + 2; 980 v->longestn = val; 981 if (fmtlen > v->width) 982 v->width = fmtlen; 983 } else if (val > 0 && val > v->longestp) { 984 fmtlen = (int)log10((double)val) + 1; 985 v->longestp = val; 986 if (fmtlen > v->width) 987 v->width = fmtlen; 988 } 989 return; 990 case VUNSIGN: 991 if (uval > v->longestu) { 992 fmtlen = (int)log10((double)uval) + 1; 993 v->longestu = uval; 994 v->width = fmtlen; 995 } 996 return; 997 case VPTR: 998 fmtlen = 0; 999 while (uval > 0) { 1000 uval >>= 4; 1001 fmtlen++; 1002 } 1003 if (fmtlen > v->width) 1004 v->width = fmtlen; 1005 return; 1006 } 1007 } 1008 1009 width = v->width; 1010 cp = ofmt + 1; 1011 fcp = v->fmt; 1012 if (v->flag & LJUST) 1013 *cp++ = '-'; 1014 *cp++ = '*'; 1015 while ((*cp++ = *fcp++) != '\0') 1016 continue; 1017 1018 switch (v->type) { 1019 case INT32: 1020 if (sizeof(int32_t) == sizeof(int)) 1021 type = INT; 1022 else if (sizeof(int32_t) == sizeof(long)) 1023 type = LONG; 1024 else 1025 errx(1, "unknown conversion for type %d", v->type); 1026 break; 1027 case UINT32: 1028 if (sizeof(u_int32_t) == sizeof(u_int)) 1029 type = UINT; 1030 else if (sizeof(u_int32_t) == sizeof(u_long)) 1031 type = ULONG; 1032 else 1033 errx(1, "unknown conversion for type %d", v->type); 1034 break; 1035 default: 1036 type = v->type; 1037 break; 1038 } 1039 1040 switch (type) { 1041 case CHAR: 1042 (void)printf(ofmt, width, GET(char)); 1043 return; 1044 case UCHAR: 1045 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1046 return; 1047 case SHORT: 1048 (void)printf(ofmt, width, GET(short)); 1049 return; 1050 case USHORT: 1051 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1052 return; 1053 case INT: 1054 (void)printf(ofmt, width, GET(int)); 1055 return; 1056 case UINT: 1057 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1058 return; 1059 case LONG: 1060 (void)printf(ofmt, width, GET(long)); 1061 return; 1062 case ULONG: 1063 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1064 return; 1065 case KPTR: 1066 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t)); 1067 return; 1068 case KPTR24: 1069 (void)printf(ofmt, width, 1070 (unsigned long long)GET(u_int64_t) & 0xffffff); 1071 return; 1072 case SIGLIST: 1073 { 1074 sigset_t *s = (sigset_t *)(void *)bp; 1075 size_t i; 1076 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1077 char buf[SIGSETSIZE * 8 + 1]; 1078 1079 for (i = 0; i < SIGSETSIZE; i++) 1080 (void)snprintf(&buf[i * 8], 9, "%.8x", 1081 s->__bits[(SIGSETSIZE - 1) - i]); 1082 1083 /* Skip leading zeroes */ 1084 for (i = 0; buf[i]; i++) 1085 if (buf[i] != '0') 1086 break; 1087 1088 if (buf[i] == '\0') 1089 i--; 1090 (void)asprintf(&obuf, ofmt, width, &buf[i]); 1091 } 1092 break; 1093 case INT64: 1094 (void)printf(ofmt, width, (long long)GET(int64_t)); 1095 return; 1096 case UINT64: 1097 (void)printf(ofmt, width, (unsigned long long)CHK_INF127(GET(u_int64_t))); 1098 return; 1099 default: 1100 errx(1, "unknown type %d", v->type); 1101 } 1102 if (obuf == NULL) 1103 err(1, "%s", ""); 1104 if (mode == WIDTHMODE) { 1105 /* Skip leading spaces. */ 1106 cp = strrchr(obuf, ' '); 1107 if (cp == NULL) 1108 cp = obuf; 1109 else 1110 cp++; /* skip last space */ 1111 } 1112 else 1113 cp = obuf; 1114 strprintorsetwidth(v, cp, mode); 1115 free(obuf); 1116 #undef GET 1117 #undef CHK_INF127 1118 } 1119 1120 void 1121 pvar(k, ve, mode) 1122 struct kinfo_proc2 *k; 1123 VARENT *ve; 1124 int mode; 1125 { 1126 VAR *v; 1127 1128 v = ve->var; 1129 printval((char *)k + v->off, v, mode); 1130 } 1131