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