1 /* $NetBSD: print.c,v 1.74 2002/06/19 08:11:55 jdolecek 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.74 2002/06/19 08:11:55 jdolecek 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 = kvm_getargv2(kd, ki, termwidth); 303 if ((p = argv) != NULL) { 304 while (*p) { 305 fmt_puts(*p, &left); 306 p++; 307 fmt_putc(' ', &left); 308 } 309 if (titlecmp(name, argv)) { 310 /* 311 * append the real command name within 312 * parentheses, if the command name 313 * does not match the one in the 314 * argument vector 315 */ 316 fmt_putc('(', &left); 317 fmt_puts(name, &left); 318 fmt_putc(')', &left); 319 } 320 } else { 321 /* 322 * Commands that don't set an argv vector 323 * are printed with square brackets if they 324 * are system commands. Otherwise they are 325 * printed within parentheses. 326 */ 327 if (ki->p_flag & P_SYSTEM) { 328 fmt_putc('[', &left); 329 fmt_puts(name, &left); 330 fmt_putc(']', &left); 331 } else { 332 fmt_putc('(', &left); 333 fmt_puts(name, &left); 334 fmt_putc(')', &left); 335 } 336 } 337 } else { 338 fmt_puts(name, &left); 339 } 340 } 341 if (ve->next && left > 0) 342 printf("%*s", left, ""); 343 } 344 345 void 346 ucomm(k, ve, mode) 347 struct kinfo_proc2 *k; 348 VARENT *ve; 349 int mode; 350 { 351 VAR *v; 352 353 v = ve->var; 354 strprintorsetwidth(v, k->p_comm, mode); 355 } 356 357 void 358 logname(k, ve, mode) 359 struct kinfo_proc2 *k; 360 VARENT *ve; 361 int mode; 362 { 363 VAR *v; 364 365 v = ve->var; 366 strprintorsetwidth(v, k->p_login, mode); 367 } 368 369 void 370 state(k, ve, mode) 371 struct kinfo_proc2 *k; 372 VARENT *ve; 373 int mode; 374 { 375 int flag, is_zombie; 376 char *cp; 377 VAR *v; 378 char buf[16]; 379 380 is_zombie = 0; 381 v = ve->var; 382 flag = k->p_flag; 383 cp = buf; 384 385 switch (k->p_stat) { 386 387 case SSTOP: 388 *cp = 'T'; 389 break; 390 391 case SSLEEP: 392 if (flag & P_SINTR) /* interuptable (long) */ 393 *cp = k->p_slptime >= maxslp ? 'I' : 'S'; 394 else 395 *cp = 'D'; 396 break; 397 398 case SRUN: 399 case SIDL: 400 case SONPROC: 401 *cp = 'R'; 402 break; 403 404 case SZOMB: 405 case SDEAD: 406 *cp = 'Z'; 407 is_zombie = 1; 408 break; 409 410 default: 411 *cp = '?'; 412 } 413 cp++; 414 if (flag & P_INMEM) { 415 } else 416 *cp++ = 'W'; 417 if (k->p_nice < NZERO) 418 *cp++ = '<'; 419 else if (k->p_nice > NZERO) 420 *cp++ = 'N'; 421 if (flag & P_TRACED) 422 *cp++ = 'X'; 423 if (flag & P_SYSTRACE) 424 *cp++ = 'x'; 425 if (flag & P_WEXIT && !is_zombie) 426 *cp++ = 'E'; 427 if (flag & P_PPWAIT) 428 *cp++ = 'V'; 429 if (flag & P_SYSTEM) 430 *cp++ = 'K'; 431 /* system process might have this too, don't need to double up */ 432 else if (k->p_holdcnt) 433 *cp++ = 'L'; 434 if (k->p_eflag & EPROC_SLEADER) 435 *cp++ = 's'; 436 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid) 437 *cp++ = '+'; 438 *cp = '\0'; 439 strprintorsetwidth(v, buf, mode); 440 } 441 442 void 443 pnice(k, ve, mode) 444 struct kinfo_proc2 *k; 445 VARENT *ve; 446 int mode; 447 { 448 VAR *v; 449 450 v = ve->var; 451 intprintorsetwidth(v, k->p_nice - NZERO, mode); 452 } 453 454 void 455 pri(k, ve, mode) 456 struct kinfo_proc2 *k; 457 VARENT *ve; 458 int mode; 459 { 460 VAR *v; 461 462 v = ve->var; 463 intprintorsetwidth(v, k->p_priority - PZERO, mode); 464 } 465 466 void 467 uname(k, ve, mode) 468 struct kinfo_proc2 *k; 469 VARENT *ve; 470 int mode; 471 { 472 VAR *v; 473 474 v = ve->var; 475 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode); 476 } 477 478 void 479 runame(k, ve, mode) 480 struct kinfo_proc2 *k; 481 VARENT *ve; 482 int mode; 483 { 484 VAR *v; 485 486 v = ve->var; 487 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode); 488 } 489 490 void 491 tdev(k, ve, mode) 492 struct kinfo_proc2 *k; 493 VARENT *ve; 494 int mode; 495 { 496 VAR *v; 497 dev_t dev; 498 char buff[16]; 499 500 v = ve->var; 501 dev = k->p_tdev; 502 if (dev == NODEV) { 503 /* 504 * Minimum width is width of header - we don't 505 * need to check it every time. 506 */ 507 if (mode == PRINTMODE) 508 (void)printf("%*s", v->width, "??"); 509 } else { 510 (void)snprintf(buff, sizeof(buff), 511 "%d/%d", major(dev), minor(dev)); 512 strprintorsetwidth(v, buff, mode); 513 } 514 } 515 516 void 517 tname(k, ve, mode) 518 struct kinfo_proc2 *k; 519 VARENT *ve; 520 int mode; 521 { 522 VAR *v; 523 dev_t dev; 524 const char *ttname; 525 int noctty; 526 527 v = ve->var; 528 dev = k->p_tdev; 529 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 530 /* 531 * Minimum width is width of header - we don't 532 * need to check it every time. 533 */ 534 if (mode == PRINTMODE) 535 (void)printf("%-*s", v->width, "??"); 536 } else { 537 if (strncmp(ttname, "tty", 3) == 0 || 538 strncmp(ttname, "dty", 3) == 0) 539 ttname += 3; 540 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0; 541 if (mode == WIDTHMODE) { 542 int fmtlen; 543 544 fmtlen = strlen(ttname) + noctty; 545 if (v->width < fmtlen) 546 v->width = fmtlen; 547 } else { 548 if (noctty) 549 printf("%-*s-", v->width - 1, ttname); 550 else 551 printf("%-*s", v->width, ttname); 552 } 553 } 554 } 555 556 void 557 longtname(k, ve, mode) 558 struct kinfo_proc2 *k; 559 VARENT *ve; 560 int mode; 561 { 562 VAR *v; 563 dev_t dev; 564 const char *ttname; 565 566 v = ve->var; 567 dev = k->p_tdev; 568 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 569 /* 570 * Minimum width is width of header - we don't 571 * need to check it every time. 572 */ 573 if (mode == PRINTMODE) 574 (void)printf("%-*s", v->width, "??"); 575 } 576 else { 577 strprintorsetwidth(v, ttname, mode); 578 } 579 } 580 581 void 582 started(k, ve, mode) 583 struct kinfo_proc2 *k; 584 VARENT *ve; 585 int mode; 586 { 587 VAR *v; 588 static time_t now; 589 time_t startt; 590 struct tm *tp; 591 char buf[100], *cp; 592 593 v = ve->var; 594 if (!k->p_uvalid) { 595 if (mode == PRINTMODE) 596 (void)printf("%*s", v->width, "-"); 597 return; 598 } 599 600 startt = k->p_ustart_sec; 601 tp = localtime(&startt); 602 if (!now) 603 (void)time(&now); 604 if (now - k->p_ustart_sec < SECSPERDAY) 605 /* I *hate* SCCS... */ 606 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 607 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 608 /* I *hate* SCCS... */ 609 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 610 else 611 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 612 /* %e and %l can start with a space. */ 613 cp = buf; 614 if (*cp == ' ') 615 cp++; 616 strprintorsetwidth(v, cp, mode); 617 } 618 619 void 620 lstarted(k, ve, mode) 621 struct kinfo_proc2 *k; 622 VARENT *ve; 623 int mode; 624 { 625 VAR *v; 626 time_t startt; 627 char buf[100]; 628 629 v = ve->var; 630 if (!k->p_uvalid) { 631 /* 632 * Minimum width is less than header - we don't 633 * need to check it every time. 634 */ 635 if (mode == PRINTMODE) 636 (void)printf("%*s", v->width, "-"); 637 return; 638 } 639 startt = k->p_ustart_sec; 640 641 /* assume all times are the same length */ 642 if (mode != WIDTHMODE || v->width == 0) { 643 (void)strftime(buf, sizeof(buf) -1, "%c", 644 localtime(&startt)); 645 strprintorsetwidth(v, buf, mode); 646 } 647 } 648 649 void 650 wchan(k, ve, mode) 651 struct kinfo_proc2 *k; 652 VARENT *ve; 653 int mode; 654 { 655 VAR *v; 656 char *buf; 657 658 v = ve->var; 659 if (k->p_wchan) { 660 if (k->p_wmesg) { 661 strprintorsetwidth(v, k->p_wmesg, mode); 662 v->width = min(v->width, WMESGLEN); 663 } else { 664 (void)asprintf(&buf, "%-*llx", v->width, 665 (long long)k->p_wchan); 666 if (buf == NULL) 667 err(1, "%s", ""); 668 strprintorsetwidth(v, buf, mode); 669 v->width = min(v->width, WMESGLEN); 670 free(buf); 671 } 672 } else { 673 if (mode == PRINTMODE) 674 (void)printf("%-*s", v->width, "-"); 675 } 676 } 677 678 #define pgtok(a) (((a)*getpagesize())/1024) 679 680 void 681 vsize(k, ve, mode) 682 struct kinfo_proc2 *k; 683 VARENT *ve; 684 int mode; 685 { 686 VAR *v; 687 688 v = ve->var; 689 intprintorsetwidth(v, 690 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode); 691 } 692 693 void 694 rssize(k, ve, mode) 695 struct kinfo_proc2 *k; 696 VARENT *ve; 697 int mode; 698 { 699 VAR *v; 700 701 v = ve->var; 702 /* XXX don't have info about shared */ 703 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 704 } 705 706 void 707 p_rssize(k, ve, mode) /* doesn't account for text */ 708 struct kinfo_proc2 *k; 709 VARENT *ve; 710 int mode; 711 { 712 VAR *v; 713 714 v = ve->var; 715 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 716 } 717 718 void 719 cputime(k, ve, mode) 720 struct kinfo_proc2 *k; 721 VARENT *ve; 722 int mode; 723 { 724 VAR *v; 725 int32_t secs; 726 int32_t psecs; /* "parts" of a second. first micro, then centi */ 727 int fmtlen; 728 729 v = ve->var; 730 if (P_ZOMBIE(k) || k->p_uvalid == 0) { 731 secs = 0; 732 psecs = 0; 733 } else { 734 /* 735 * This counts time spent handling interrupts. We could 736 * fix this, but it is not 100% trivial (and interrupt 737 * time fractions only work on the sparc anyway). XXX 738 */ 739 secs = k->p_rtime_sec; 740 psecs = k->p_rtime_usec; 741 if (sumrusage) { 742 secs += k->p_uctime_sec; 743 psecs += k->p_uctime_usec; 744 } 745 /* 746 * round and scale to 100's 747 */ 748 psecs = (psecs + 5000) / 10000; 749 secs += psecs / 100; 750 psecs = psecs % 100; 751 } 752 if (mode == WIDTHMODE) { 753 /* 754 * Ugg, this is the only field where a value of 0 longer 755 * than the column title, and log10(0) isn't good enough. 756 * Use SECSPERMIN, because secs is divided by that when 757 * passed to log10(). 758 */ 759 if (secs == 0 && v->longestp == 0) 760 secs = SECSPERMIN; 761 if (secs > v->longestp) { 762 /* "+6" for the "%02ld.%02ld" in the printf() below */ 763 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6; 764 v->longestp = secs; 765 if (fmtlen > v->width) 766 v->width = fmtlen; 767 } 768 } else { 769 printf("%*ld:%02ld.%02ld", v->width - 6, (long)(secs / SECSPERMIN), 770 (long)(secs % SECSPERMIN), (long)psecs); 771 } 772 } 773 774 double 775 getpcpu(k) 776 struct kinfo_proc2 *k; 777 { 778 static int failure; 779 780 if (!nlistread) 781 failure = (kd) ? donlist() : 1; 782 if (failure) 783 return (0.0); 784 785 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 786 787 /* XXX - I don't like this */ 788 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 || 789 k->p_stat == SZOMB || k->p_stat == SDEAD) 790 return (0.0); 791 if (rawcpu) 792 return (100.0 * fxtofl(k->p_pctcpu)); 793 return (100.0 * fxtofl(k->p_pctcpu) / 794 (1.0 - exp(k->p_swtime * log(ccpu)))); 795 } 796 797 void 798 pcpu(k, ve, mode) 799 struct kinfo_proc2 *k; 800 VARENT *ve; 801 int mode; 802 { 803 VAR *v; 804 805 v = ve->var; 806 doubleprintorsetwidth(v, getpcpu(k), 1, mode); 807 } 808 809 double 810 getpmem(k) 811 struct kinfo_proc2 *k; 812 { 813 static int failure; 814 double fracmem; 815 int szptudot; 816 817 if (!nlistread) 818 failure = (kd) ? donlist() : 1; 819 if (failure) 820 return (0.0); 821 822 if ((k->p_flag & P_INMEM) == 0) 823 return (0.0); 824 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 825 szptudot = uspace/getpagesize(); 826 /* XXX don't have info about shared */ 827 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 828 return (100.0 * fracmem); 829 } 830 831 void 832 pmem(k, ve, mode) 833 struct kinfo_proc2 *k; 834 VARENT *ve; 835 int mode; 836 { 837 VAR *v; 838 839 v = ve->var; 840 doubleprintorsetwidth(v, getpmem(k), 1, mode); 841 } 842 843 void 844 pagein(k, ve, mode) 845 struct kinfo_proc2 *k; 846 VARENT *ve; 847 int mode; 848 { 849 VAR *v; 850 851 v = ve->var; 852 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 853 } 854 855 void 856 maxrss(k, ve, mode) 857 struct kinfo_proc2 *k; 858 VARENT *ve; 859 int mode; 860 { 861 VAR *v; 862 863 v = ve->var; 864 /* No need to check width! */ 865 if (mode == PRINTMODE) 866 (void)printf("%*s", v->width, "-"); 867 } 868 869 void 870 tsize(k, ve, mode) 871 struct kinfo_proc2 *k; 872 VARENT *ve; 873 int mode; 874 { 875 VAR *v; 876 877 v = ve->var; 878 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 879 } 880 881 /* 882 * Generic output routines. Print fields from various prototype 883 * structures. 884 */ 885 static void 886 printval(bp, v, mode) 887 void *bp; 888 VAR *v; 889 int mode; 890 { 891 static char ofmt[32] = "%"; 892 int width, vok, fmtlen; 893 char *fcp, *cp, *obuf; 894 enum type type; 895 long long val; 896 unsigned long long uval; 897 898 /* 899 * Note that the "INF127" check is nonsensical for types 900 * that are or can be signed. 901 */ 902 #define GET(type) (*(type *)bp) 903 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 904 905 #define VSIGN 1 906 #define VUNSIGN 2 907 #define VPTR 3 908 909 if (mode == WIDTHMODE) { 910 vok = 0; 911 switch (v->type) { 912 case CHAR: 913 val = GET(char); 914 vok = VSIGN; 915 break; 916 case UCHAR: 917 uval = CHK_INF127(GET(u_char)); 918 vok = VUNSIGN; 919 break; 920 case SHORT: 921 val = GET(short); 922 vok = VSIGN; 923 break; 924 case USHORT: 925 uval = CHK_INF127(GET(u_short)); 926 vok = VUNSIGN; 927 break; 928 case INT32: 929 val = GET(int32_t); 930 vok = VSIGN; 931 break; 932 case INT: 933 val = GET(int); 934 vok = VSIGN; 935 break; 936 case UINT: 937 case UINT32: 938 uval = CHK_INF127(GET(u_int)); 939 vok = VUNSIGN; 940 break; 941 case LONG: 942 val = GET(long); 943 vok = VSIGN; 944 break; 945 case ULONG: 946 uval = CHK_INF127(GET(u_long)); 947 vok = VUNSIGN; 948 break; 949 case KPTR: 950 uval = (unsigned long long)GET(u_int64_t); 951 vok = VPTR; 952 break; 953 case KPTR24: 954 uval = (unsigned long long)GET(u_int64_t); 955 uval &= 0xffffff; 956 vok = VPTR; 957 break; 958 case INT64: 959 val = (long long)GET(int64_t); 960 vok = VSIGN; 961 break; 962 case UINT64: 963 uval = (unsigned long long)CHK_INF127(GET(u_int64_t)); 964 vok = VUNSIGN; 965 break; 966 967 default: 968 /* nothing... */; 969 } 970 switch (vok) { 971 case VSIGN: 972 if (val < 0 && val < v->longestn) { 973 fmtlen = (int)log10((double)-val) + 2; 974 v->longestn = val; 975 if (fmtlen > v->width) 976 v->width = fmtlen; 977 } else if (val > 0 && val > v->longestp) { 978 fmtlen = (int)log10((double)val) + 1; 979 v->longestp = val; 980 if (fmtlen > v->width) 981 v->width = fmtlen; 982 } 983 return; 984 case VUNSIGN: 985 if (uval > v->longestu) { 986 fmtlen = (int)log10((double)uval) + 1; 987 v->longestu = uval; 988 v->width = fmtlen; 989 } 990 return; 991 case VPTR: 992 fmtlen = 0; 993 while (uval > 0) { 994 uval >>= 4; 995 fmtlen++; 996 } 997 if (fmtlen > v->width) 998 v->width = fmtlen; 999 return; 1000 } 1001 } 1002 1003 width = v->width; 1004 cp = ofmt + 1; 1005 fcp = v->fmt; 1006 if (v->flag & LJUST) 1007 *cp++ = '-'; 1008 *cp++ = '*'; 1009 while ((*cp++ = *fcp++) != '\0') 1010 continue; 1011 1012 switch (v->type) { 1013 case INT32: 1014 if (sizeof(int32_t) == sizeof(int)) 1015 type = INT; 1016 else if (sizeof(int32_t) == sizeof(long)) 1017 type = LONG; 1018 else 1019 errx(1, "unknown conversion for type %d", v->type); 1020 break; 1021 case UINT32: 1022 if (sizeof(u_int32_t) == sizeof(u_int)) 1023 type = UINT; 1024 else if (sizeof(u_int32_t) == sizeof(u_long)) 1025 type = ULONG; 1026 else 1027 errx(1, "unknown conversion for type %d", v->type); 1028 break; 1029 default: 1030 type = v->type; 1031 break; 1032 } 1033 1034 switch (type) { 1035 case CHAR: 1036 (void)printf(ofmt, width, GET(char)); 1037 return; 1038 case UCHAR: 1039 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1040 return; 1041 case SHORT: 1042 (void)printf(ofmt, width, GET(short)); 1043 return; 1044 case USHORT: 1045 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1046 return; 1047 case INT: 1048 (void)printf(ofmt, width, GET(int)); 1049 return; 1050 case UINT: 1051 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1052 return; 1053 case LONG: 1054 (void)printf(ofmt, width, GET(long)); 1055 return; 1056 case ULONG: 1057 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1058 return; 1059 case KPTR: 1060 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t)); 1061 return; 1062 case KPTR24: 1063 (void)printf(ofmt, width, 1064 (unsigned long long)GET(u_int64_t) & 0xffffff); 1065 return; 1066 case SIGLIST: 1067 { 1068 sigset_t *s = (sigset_t *)(void *)bp; 1069 size_t i; 1070 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1071 char buf[SIGSETSIZE * 8 + 1]; 1072 1073 for (i = 0; i < SIGSETSIZE; i++) 1074 (void)snprintf(&buf[i * 8], 9, "%.8x", 1075 s->__bits[(SIGSETSIZE - 1) - i]); 1076 1077 /* Skip leading zeroes */ 1078 for (i = 0; buf[i]; i++) 1079 if (buf[i] != '0') 1080 break; 1081 1082 if (buf[i] == '\0') 1083 i--; 1084 (void)asprintf(&obuf, ofmt, width, &buf[i]); 1085 } 1086 break; 1087 case INT64: 1088 (void)printf(ofmt, width, (long long)GET(int64_t)); 1089 return; 1090 case UINT64: 1091 (void)printf(ofmt, width, (unsigned long long)CHK_INF127(GET(u_int64_t))); 1092 return; 1093 default: 1094 errx(1, "unknown type %d", v->type); 1095 } 1096 if (obuf == NULL) 1097 err(1, "%s", ""); 1098 if (mode == WIDTHMODE) { 1099 /* Skip leading spaces. */ 1100 cp = strrchr(obuf, ' '); 1101 if (cp == NULL) 1102 cp = obuf; 1103 else 1104 cp++; /* skip last space */ 1105 } 1106 else 1107 cp = obuf; 1108 strprintorsetwidth(v, cp, mode); 1109 free(obuf); 1110 #undef GET 1111 #undef CHK_INF127 1112 } 1113 1114 void 1115 pvar(k, ve, mode) 1116 struct kinfo_proc2 *k; 1117 VARENT *ve; 1118 int mode; 1119 { 1120 VAR *v; 1121 1122 v = ve->var; 1123 printval((char *)k + v->off, v, mode); 1124 } 1125