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