1 /* $NetBSD: print.c,v 1.69 2001/08/24 06:37:03 lukem 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.69 2001/08/24 06:37:03 lukem 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 /* 600 * XXX: The maximum width of this field is the same as the header 601 * "STARTED" for locales that have 3 letter abbreviated month 602 * names and 2 letter am/pm descriptions. 603 */ 604 if (mode == WIDTHMODE) 605 return; 606 607 v = ve->var; 608 if (!k->p_uvalid) { 609 if (mode == PRINTMODE) 610 (void)printf("%*s", v->width, "-"); 611 return; 612 } 613 614 startt = k->p_ustart_sec; 615 tp = localtime(&startt); 616 if (!now) 617 (void)time(&now); 618 if (now - k->p_ustart_sec < SECSPERDAY) 619 /* I *hate* SCCS... */ 620 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 621 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 622 /* I *hate* SCCS... */ 623 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 624 else 625 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 626 /* %e and %l can start with a space. */ 627 cp = buf; 628 if (*cp == ' ') 629 cp++; 630 strprintorsetwidth(v, cp, mode); 631 } 632 633 void 634 lstarted(k, ve, mode) 635 struct kinfo_proc2 *k; 636 VARENT *ve; 637 int mode; 638 { 639 VAR *v; 640 time_t startt; 641 char buf[100]; 642 643 v = ve->var; 644 if (!k->p_uvalid) { 645 /* 646 * Minimum width is less than header - we don't 647 * need to check it every time. 648 */ 649 if (mode == PRINTMODE) 650 (void)printf("%*s", v->width, "-"); 651 return; 652 } 653 startt = k->p_ustart_sec; 654 655 /* assume all times are the same length */ 656 if (mode != WIDTHMODE || v->width == 0) { 657 (void)strftime(buf, sizeof(buf) -1, "%c", 658 localtime(&startt)); 659 strprintorsetwidth(v, buf, mode); 660 } 661 } 662 663 void 664 wchan(k, ve, mode) 665 struct kinfo_proc2 *k; 666 VARENT *ve; 667 int mode; 668 { 669 VAR *v; 670 char *buf; 671 672 v = ve->var; 673 if (k->p_wchan) { 674 if (k->p_wmesg) { 675 strprintorsetwidth(v, k->p_wmesg, mode); 676 v->width = min(v->width, WMESGLEN); 677 } else { 678 (void)asprintf(&buf, "%-*llx", v->width, 679 (long long)k->p_wchan); 680 if (buf == NULL) 681 err(1, "%s", ""); 682 strprintorsetwidth(v, buf, mode); 683 v->width = min(v->width, WMESGLEN); 684 free(buf); 685 } 686 } else { 687 if (mode == PRINTMODE) 688 (void)printf("%-*s", v->width, "-"); 689 } 690 } 691 692 #define pgtok(a) (((a)*getpagesize())/1024) 693 694 void 695 vsize(k, ve, mode) 696 struct kinfo_proc2 *k; 697 VARENT *ve; 698 int mode; 699 { 700 VAR *v; 701 702 v = ve->var; 703 intprintorsetwidth(v, 704 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode); 705 } 706 707 void 708 rssize(k, ve, mode) 709 struct kinfo_proc2 *k; 710 VARENT *ve; 711 int mode; 712 { 713 VAR *v; 714 715 v = ve->var; 716 /* XXX don't have info about shared */ 717 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 718 } 719 720 void 721 p_rssize(k, ve, mode) /* doesn't account for text */ 722 struct kinfo_proc2 *k; 723 VARENT *ve; 724 int mode; 725 { 726 VAR *v; 727 728 v = ve->var; 729 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 730 } 731 732 void 733 cputime(k, ve, mode) 734 struct kinfo_proc2 *k; 735 VARENT *ve; 736 int mode; 737 { 738 VAR *v; 739 long secs; 740 long psecs; /* "parts" of a second. first micro, then centi */ 741 int fmtlen; 742 743 v = ve->var; 744 if (P_ZOMBIE(k) || k->p_uvalid == 0) { 745 secs = 0; 746 psecs = 0; 747 } else { 748 /* 749 * This counts time spent handling interrupts. We could 750 * fix this, but it is not 100% trivial (and interrupt 751 * time fractions only work on the sparc anyway). XXX 752 */ 753 secs = k->p_rtime_sec; 754 psecs = k->p_rtime_usec; 755 if (sumrusage) { 756 secs += k->p_uctime_sec; 757 psecs += k->p_uctime_usec; 758 } 759 /* 760 * round and scale to 100's 761 */ 762 psecs = (psecs + 5000) / 10000; 763 secs += psecs / 100; 764 psecs = psecs % 100; 765 } 766 if (mode == WIDTHMODE) { 767 /* 768 * Ugg, this is the only field where a value of 0 longer 769 * than the column title, and log10(0) isn't good enough. 770 * Use SECSPERMIN, because secs is divided by that when 771 * passed to log10(). 772 */ 773 if (secs == 0 && v->longestp == 0) 774 secs = SECSPERMIN; 775 if (secs > v->longestp) { 776 /* "+6" for the "%02ld.%02ld" in the printf() below */ 777 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6; 778 v->longestp = secs; 779 if (fmtlen > v->width) 780 v->width = fmtlen; 781 } 782 } else { 783 printf("%*ld:%02ld.%02ld", v->width - 6, secs / SECSPERMIN, 784 secs % SECSPERMIN, psecs); 785 } 786 } 787 788 double 789 getpcpu(k) 790 struct kinfo_proc2 *k; 791 { 792 static int failure; 793 794 if (!nlistread) 795 failure = (kd) ? donlist() : 1; 796 if (failure) 797 return (0.0); 798 799 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 800 801 /* XXX - I don't like this */ 802 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 || 803 k->p_stat == SZOMB || k->p_stat == SDEAD) 804 return (0.0); 805 if (rawcpu) 806 return (100.0 * fxtofl(k->p_pctcpu)); 807 return (100.0 * fxtofl(k->p_pctcpu) / 808 (1.0 - exp(k->p_swtime * log(ccpu)))); 809 } 810 811 void 812 pcpu(k, ve, mode) 813 struct kinfo_proc2 *k; 814 VARENT *ve; 815 int mode; 816 { 817 VAR *v; 818 819 v = ve->var; 820 doubleprintorsetwidth(v, getpcpu(k), 1, mode); 821 } 822 823 double 824 getpmem(k) 825 struct kinfo_proc2 *k; 826 { 827 static int failure; 828 double fracmem; 829 int szptudot; 830 831 if (!nlistread) 832 failure = (kd) ? donlist() : 1; 833 if (failure) 834 return (0.0); 835 836 if ((k->p_flag & P_INMEM) == 0) 837 return (0.0); 838 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 839 szptudot = uspace/getpagesize(); 840 /* XXX don't have info about shared */ 841 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 842 return (100.0 * fracmem); 843 } 844 845 void 846 pmem(k, ve, mode) 847 struct kinfo_proc2 *k; 848 VARENT *ve; 849 int mode; 850 { 851 VAR *v; 852 853 v = ve->var; 854 doubleprintorsetwidth(v, getpmem(k), 1, mode); 855 } 856 857 void 858 pagein(k, ve, mode) 859 struct kinfo_proc2 *k; 860 VARENT *ve; 861 int mode; 862 { 863 VAR *v; 864 865 v = ve->var; 866 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 867 } 868 869 void 870 maxrss(k, ve, mode) 871 struct kinfo_proc2 *k; 872 VARENT *ve; 873 int mode; 874 { 875 VAR *v; 876 877 v = ve->var; 878 /* No need to check width! */ 879 if (mode == PRINTMODE) 880 (void)printf("%*s", v->width, "-"); 881 } 882 883 void 884 tsize(k, ve, mode) 885 struct kinfo_proc2 *k; 886 VARENT *ve; 887 int mode; 888 { 889 VAR *v; 890 891 v = ve->var; 892 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 893 } 894 895 /* 896 * Generic output routines. Print fields from various prototype 897 * structures. 898 */ 899 static void 900 printval(bp, v, mode) 901 void *bp; 902 VAR *v; 903 int mode; 904 { 905 static char ofmt[32] = "%"; 906 int width, vok, fmtlen; 907 char *fcp, *cp, *obuf; 908 enum type type; 909 long long val; 910 unsigned long long uval; 911 912 /* 913 * Note that the "INF127" check is nonsensical for types 914 * that are or can be signed. 915 */ 916 #define GET(type) (*(type *)bp) 917 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 918 919 #define VSIGN 1 920 #define VUNSIGN 2 921 #define VPTR 3 922 923 if (mode == WIDTHMODE) { 924 vok = 0; 925 switch (v->type) { 926 case CHAR: 927 val = GET(char); 928 vok = VSIGN; 929 break; 930 case UCHAR: 931 uval = CHK_INF127(GET(u_char)); 932 vok = VUNSIGN; 933 break; 934 case SHORT: 935 val = GET(short); 936 vok = VSIGN; 937 break; 938 case USHORT: 939 uval = CHK_INF127(GET(u_short)); 940 vok = VUNSIGN; 941 break; 942 case INT32: 943 val = GET(int32_t); 944 vok = VSIGN; 945 break; 946 case INT: 947 val = GET(int); 948 vok = VSIGN; 949 break; 950 case UINT: 951 case UINT32: 952 uval = CHK_INF127(GET(u_int)); 953 vok = VUNSIGN; 954 break; 955 case LONG: 956 val = GET(long); 957 vok = VSIGN; 958 break; 959 case ULONG: 960 uval = CHK_INF127(GET(u_long)); 961 vok = VUNSIGN; 962 break; 963 case KPTR: 964 uval = (unsigned long long)GET(u_int64_t); 965 vok = VPTR; 966 break; 967 case KPTR24: 968 uval = (unsigned long long)GET(u_int64_t); 969 uval &= 0xffffff; 970 vok = VPTR; 971 break; 972 default: 973 /* nothing... */; 974 } 975 switch (vok) { 976 case VSIGN: 977 if (val < 0 && val < v->longestn) { 978 fmtlen = (int)log10((double)-val) + 2; 979 v->longestn = val; 980 if (fmtlen > v->width) 981 v->width = fmtlen; 982 } else if (val > 0 && val > v->longestp) { 983 fmtlen = (int)log10((double)val) + 1; 984 v->longestp = val; 985 if (fmtlen > v->width) 986 v->width = fmtlen; 987 } 988 return; 989 case VUNSIGN: 990 if (uval > v->longestu) { 991 fmtlen = (int)log10((double)uval) + 1; 992 v->longestu = uval; 993 v->width = fmtlen; 994 } 995 return; 996 case VPTR: 997 fmtlen = 0; 998 while (uval > 0) { 999 uval >>= 4; 1000 fmtlen++; 1001 } 1002 if (fmtlen > v->width) 1003 v->width = fmtlen; 1004 return; 1005 } 1006 } 1007 1008 width = v->width; 1009 cp = ofmt + 1; 1010 fcp = v->fmt; 1011 if (v->flag & LJUST) 1012 *cp++ = '-'; 1013 *cp++ = '*'; 1014 while ((*cp++ = *fcp++) != '\0') 1015 continue; 1016 1017 switch (v->type) { 1018 case INT32: 1019 if (sizeof(int32_t) == sizeof(int)) 1020 type = INT; 1021 else if (sizeof(int32_t) == sizeof(long)) 1022 type = LONG; 1023 else 1024 errx(1, "unknown conversion for type %d", v->type); 1025 break; 1026 case UINT32: 1027 if (sizeof(u_int32_t) == sizeof(u_int)) 1028 type = UINT; 1029 else if (sizeof(u_int32_t) == sizeof(u_long)) 1030 type = ULONG; 1031 else 1032 errx(1, "unknown conversion for type %d", v->type); 1033 break; 1034 default: 1035 type = v->type; 1036 break; 1037 } 1038 1039 switch (type) { 1040 case CHAR: 1041 (void)printf(ofmt, width, GET(char)); 1042 return; 1043 case UCHAR: 1044 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1045 return; 1046 case SHORT: 1047 (void)printf(ofmt, width, GET(short)); 1048 return; 1049 case USHORT: 1050 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1051 return; 1052 case INT: 1053 (void)printf(ofmt, width, GET(int)); 1054 return; 1055 case UINT: 1056 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1057 return; 1058 case LONG: 1059 (void)printf(ofmt, width, GET(long)); 1060 return; 1061 case ULONG: 1062 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1063 return; 1064 case KPTR: 1065 (void)printf(ofmt, width, (unsigned long long)GET(u_int64_t)); 1066 return; 1067 case KPTR24: 1068 (void)printf(ofmt, width, 1069 (unsigned long long)GET(u_int64_t) & 0xffffff); 1070 return; 1071 case SIGLIST: 1072 { 1073 sigset_t *s = (sigset_t *)(void *)bp; 1074 size_t i; 1075 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1076 char buf[SIGSETSIZE * 8 + 1]; 1077 1078 for (i = 0; i < SIGSETSIZE; i++) 1079 (void)snprintf(&buf[i * 8], 9, "%.8x", 1080 s->__bits[(SIGSETSIZE - 1) - i]); 1081 1082 /* Skip leading zeroes */ 1083 for (i = 0; buf[i]; i++) 1084 if (buf[i] != '0') 1085 break; 1086 1087 if (buf[i] == '\0') 1088 i--; 1089 (void)asprintf(&obuf, ofmt, width, &buf[i]); 1090 } 1091 break; 1092 default: 1093 errx(1, "unknown type %d", v->type); 1094 } 1095 if (obuf == NULL) 1096 err(1, "%s", ""); 1097 if (mode == WIDTHMODE) { 1098 /* Skip leading spaces. */ 1099 cp = strrchr(obuf, ' '); 1100 if (cp == NULL) 1101 cp = obuf; 1102 else 1103 cp++; /* skip last space */ 1104 } 1105 else 1106 cp = obuf; 1107 strprintorsetwidth(v, cp, mode); 1108 free(obuf); 1109 #undef GET 1110 #undef CHK_INF127 1111 } 1112 1113 void 1114 pvar(k, ve, mode) 1115 struct kinfo_proc2 *k; 1116 VARENT *ve; 1117 int mode; 1118 { 1119 VAR *v; 1120 1121 v = ve->var; 1122 printval((char *)k + v->off, v, mode); 1123 } 1124