1 /* $NetBSD: print.c,v 1.49 1999/12/05 18:33:28 fredb Exp $ */ 2 3 /*- 4 * Copyright (c) 1990, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; 40 #else 41 __RCSID("$NetBSD: print.c,v 1.49 1999/12/05 18:33:28 fredb Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/time.h> 47 #include <sys/resource.h> 48 #include <sys/proc.h> 49 #include <sys/stat.h> 50 #include <sys/ucred.h> 51 #include <sys/sysctl.h> 52 53 #include <vm/vm.h> 54 55 #include <err.h> 56 #include <kvm.h> 57 #include <math.h> 58 #include <nlist.h> 59 #include <pwd.h> 60 #include <stddef.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <time.h> 65 #include <tzfile.h> 66 #include <unistd.h> 67 68 #include "ps.h" 69 70 static char *cmdpart __P((char *)); 71 static void printval __P((char *, VAR *)); 72 static int titlecmp __P((char *, char **)); 73 74 #define min(a,b) ((a) <= (b) ? (a) : (b)) 75 #define max(a,b) ((a) >= (b) ? (a) : (b)) 76 77 static char * 78 cmdpart(arg0) 79 char *arg0; 80 { 81 char *cp; 82 83 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 84 } 85 86 void 87 printheader() 88 { 89 VAR *v; 90 struct varent *vent; 91 92 for (vent = vhead; vent; vent = vent->next) { 93 v = vent->var; 94 if (v->flag & LJUST) { 95 if (vent->next == NULL) /* last one */ 96 (void)printf("%s", v->header); 97 else 98 (void)printf("%-*s", v->width, v->header); 99 } else 100 (void)printf("%*s", v->width, v->header); 101 if (vent->next != NULL) 102 (void)putchar(' '); 103 } 104 (void)putchar('\n'); 105 } 106 107 static int 108 titlecmp(name, argv) 109 char *name; 110 char **argv; 111 { 112 char *title; 113 int namelen; 114 115 if (argv == 0 || argv[0] == 0) 116 return (1); 117 118 title = cmdpart(argv[0]); 119 120 if (!strcmp(name, title)) 121 return (0); 122 123 if (title[0] == '-' && !strcmp(name, title+1)) 124 return (0); 125 126 namelen = strlen(name); 127 128 if (argv[1] == 0 && 129 !strncmp(name, title, namelen) && 130 title[namelen+0] == ':' && 131 title[namelen+1] == ' ') 132 return (0); 133 134 return (1); 135 } 136 137 void 138 command(ki, ve) 139 KINFO *ki; 140 VARENT *ve; 141 { 142 VAR *v; 143 int left; 144 char **argv, **p, *name; 145 146 v = ve->var; 147 if (ve->next != NULL || termwidth != UNLIMITED) { 148 if (ve->next == NULL) { 149 left = termwidth - (totwidth - v->width); 150 if (left < 1) /* already wrapped, just use std width */ 151 left = v->width; 152 } else 153 left = v->width; 154 } else 155 left = -1; 156 if (needenv && (myuid == 0 || KI_EPROC(ki)->e_ucred.cr_uid == myuid) && 157 kd) { 158 argv = kvm_getenvv(kd, ki->ki_p, termwidth); 159 if ((p = argv) != NULL) { 160 while (*p) { 161 fmt_puts(*p, &left); 162 p++; 163 fmt_putc(' ', &left); 164 } 165 } 166 } 167 if (needcomm) { 168 name = KI_PROC(ki)->p_comm; 169 if (!commandonly) { 170 argv = NULL; 171 if (!use_procfs) 172 argv = kvm_getargv(kd, ki->ki_p, termwidth); 173 else 174 argv = procfs_getargv(ki->ki_p, termwidth); 175 if ((p = argv) != NULL) { 176 while (*p) { 177 fmt_puts(*p, &left); 178 p++; 179 fmt_putc(' ', &left); 180 } 181 } 182 if (titlecmp(name, argv)) { 183 fmt_putc('(', &left); 184 fmt_puts(name, &left); 185 fmt_putc(')', &left); 186 } 187 if (use_procfs && argv) { 188 free(argv[0]); 189 free(argv); 190 } 191 } else { 192 fmt_puts(name, &left); 193 } 194 } 195 if (ve->next && left > 0) 196 printf("%*s", left, ""); 197 } 198 199 void 200 ucomm(k, ve) 201 KINFO *k; 202 VARENT *ve; 203 { 204 VAR *v; 205 206 v = ve->var; 207 (void)printf("%-*s", v->width, KI_PROC(k)->p_comm); 208 } 209 210 void 211 logname(k, ve) 212 KINFO *k; 213 VARENT *ve; 214 { 215 VAR *v; 216 int n; 217 218 v = ve->var; 219 n = min(v->width, MAXLOGNAME); 220 (void)printf("%-*.*s", n, n, KI_EPROC(k)->e_login); 221 if (v->width > n) 222 (void)printf("%*s", v->width - n, ""); 223 } 224 225 void 226 state(k, ve) 227 KINFO *k; 228 VARENT *ve; 229 { 230 struct proc *p; 231 int flag; 232 char *cp; 233 VAR *v; 234 char buf[16]; 235 236 v = ve->var; 237 p = KI_PROC(k); 238 flag = p->p_flag; 239 cp = buf; 240 241 switch (p->p_stat) { 242 243 case SSTOP: 244 *cp = 'T'; 245 break; 246 247 case SSLEEP: 248 if (flag & P_SINTR) /* interuptable (long) */ 249 *cp = p->p_slptime >= MAXSLP ? 'I' : 'S'; 250 else 251 *cp = 'D'; 252 break; 253 254 case SRUN: 255 case SIDL: 256 *cp = 'R'; 257 break; 258 259 case SZOMB: 260 case SDEAD: 261 *cp = 'Z'; 262 break; 263 264 default: 265 *cp = '?'; 266 } 267 cp++; 268 if (flag & P_INMEM) { 269 } else 270 *cp++ = 'W'; 271 if (p->p_nice < NZERO) 272 *cp++ = '<'; 273 else if (p->p_nice > NZERO) 274 *cp++ = 'N'; 275 if (flag & P_TRACED) 276 *cp++ = 'X'; 277 if (flag & P_WEXIT && P_ZOMBIE(p) == 0) 278 *cp++ = 'E'; 279 if (flag & P_PPWAIT) 280 *cp++ = 'V'; 281 if ((flag & P_SYSTEM) || p->p_holdcnt) 282 *cp++ = 'L'; 283 if (KI_EPROC(k)->e_flag & EPROC_SLEADER) 284 *cp++ = 's'; 285 if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid) 286 *cp++ = '+'; 287 *cp = '\0'; 288 (void)printf("%-*s", v->width, buf); 289 } 290 291 void 292 pnice(k, ve) 293 KINFO *k; 294 VARENT *ve; 295 { 296 VAR *v; 297 298 v = ve->var; 299 (void)printf("%*d", v->width, KI_PROC(k)->p_nice - NZERO); 300 } 301 302 void 303 pri(k, ve) 304 KINFO *k; 305 VARENT *ve; 306 { 307 VAR *v; 308 309 v = ve->var; 310 (void)printf("%*d", v->width, KI_PROC(k)->p_priority - PZERO); 311 } 312 313 void 314 uname(k, ve) 315 KINFO *k; 316 VARENT *ve; 317 { 318 VAR *v; 319 320 v = ve->var; 321 (void)printf("%-*s", 322 (int)v->width, user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)); 323 } 324 325 void 326 runame(k, ve) 327 KINFO *k; 328 VARENT *ve; 329 { 330 VAR *v; 331 332 v = ve->var; 333 (void)printf("%-*s", 334 (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0)); 335 } 336 337 void 338 tdev(k, ve) 339 KINFO *k; 340 VARENT *ve; 341 { 342 VAR *v; 343 dev_t dev; 344 char buff[16]; 345 346 v = ve->var; 347 dev = KI_EPROC(k)->e_tdev; 348 if (dev == NODEV) 349 (void)printf("%*s", v->width, "??"); 350 else { 351 (void)snprintf(buff, sizeof(buff), 352 "%d/%d", major(dev), minor(dev)); 353 (void)printf("%*s", v->width, buff); 354 } 355 } 356 357 void 358 tname(k, ve) 359 KINFO *k; 360 VARENT *ve; 361 { 362 VAR *v; 363 dev_t dev; 364 const char *ttname; 365 366 v = ve->var; 367 dev = KI_EPROC(k)->e_tdev; 368 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 369 (void)printf("%-*s", v->width, "??"); 370 else { 371 if (strncmp(ttname, "tty", 3) == 0 || 372 strncmp(ttname, "dty", 3) == 0) 373 ttname += 3; 374 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, 375 KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-'); 376 } 377 } 378 379 void 380 longtname(k, ve) 381 KINFO *k; 382 VARENT *ve; 383 { 384 VAR *v; 385 dev_t dev; 386 const char *ttname; 387 388 v = ve->var; 389 dev = KI_EPROC(k)->e_tdev; 390 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 391 (void)printf("%-*s", v->width, "??"); 392 else 393 (void)printf("%-*s", v->width, ttname); 394 } 395 396 void 397 started(k, ve) 398 KINFO *k; 399 VARENT *ve; 400 { 401 VAR *v; 402 static time_t now; 403 time_t startt; 404 struct tm *tp; 405 char buf[100]; 406 407 v = ve->var; 408 if (!k->ki_u.u_valid) { 409 (void)printf("%-*s", v->width, "-"); 410 return; 411 } 412 413 startt = k->ki_u.u_start.tv_sec; 414 tp = localtime(&startt); 415 if (!now) 416 (void)time(&now); 417 if (now - k->ki_u.u_start.tv_sec < 24 * SECSPERHOUR) { 418 /* I *hate* SCCS... */ 419 static char fmt[] = __CONCAT("%l:%", "M%p"); 420 (void)strftime(buf, sizeof(buf) - 1, fmt, tp); 421 } else if (now - k->ki_u.u_start.tv_sec < 7 * SECSPERDAY) { 422 /* I *hate* SCCS... */ 423 static char fmt[] = __CONCAT("%a%", "I%p"); 424 (void)strftime(buf, sizeof(buf) - 1, fmt, tp); 425 } else 426 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 427 (void)printf("%-*s", v->width, buf); 428 } 429 430 void 431 lstarted(k, ve) 432 KINFO *k; 433 VARENT *ve; 434 { 435 VAR *v; 436 time_t startt; 437 char buf[100]; 438 439 v = ve->var; 440 if (!k->ki_u.u_valid) { 441 (void)printf("%-*s", v->width, "-"); 442 return; 443 } 444 startt = k->ki_u.u_start.tv_sec; 445 (void)strftime(buf, sizeof(buf) -1, "%c", 446 localtime(&startt)); 447 (void)printf("%-*s", v->width, buf); 448 } 449 450 void 451 wchan(k, ve) 452 KINFO *k; 453 VARENT *ve; 454 { 455 VAR *v; 456 int n; 457 458 v = ve->var; 459 if (KI_PROC(k)->p_wchan) { 460 if (KI_PROC(k)->p_wmesg) { 461 n = min(v->width, WMESGLEN); 462 (void)printf("%-*.*s", n, n, KI_EPROC(k)->e_wmesg); 463 if (v->width > n) 464 (void)printf("%*s", v->width - n, ""); 465 } else 466 (void)printf("%-*lx", v->width, 467 (long)KI_PROC(k)->p_wchan); 468 } else 469 (void)printf("%-*s", v->width, "-"); 470 } 471 472 #define pgtok(a) (((a)*getpagesize())/1024) 473 474 void 475 vsize(k, ve) 476 KINFO *k; 477 VARENT *ve; 478 { 479 VAR *v; 480 481 v = ve->var; 482 (void)printf("%*d", v->width, 483 pgtok(KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + 484 KI_EPROC(k)->e_vm.vm_tsize)); 485 } 486 487 void 488 rssize(k, ve) 489 KINFO *k; 490 VARENT *ve; 491 { 492 VAR *v; 493 494 v = ve->var; 495 /* XXX don't have info about shared */ 496 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize)); 497 } 498 499 void 500 p_rssize(k, ve) /* doesn't account for text */ 501 KINFO *k; 502 VARENT *ve; 503 { 504 VAR *v; 505 506 v = ve->var; 507 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize)); 508 } 509 510 void 511 cputime(k, ve) 512 KINFO *k; 513 VARENT *ve; 514 { 515 VAR *v; 516 long secs; 517 long psecs; /* "parts" of a second. first micro, then centi */ 518 char obuff[128]; 519 520 v = ve->var; 521 if (P_ZOMBIE(KI_PROC(k)) || k->ki_u.u_valid == 0) { 522 secs = 0; 523 psecs = 0; 524 } else { 525 /* 526 * This counts time spent handling interrupts. We could 527 * fix this, but it is not 100% trivial (and interrupt 528 * time fractions only work on the sparc anyway). XXX 529 */ 530 secs = KI_PROC(k)->p_rtime.tv_sec; 531 psecs = KI_PROC(k)->p_rtime.tv_usec; 532 if (sumrusage) { 533 secs += k->ki_u.u_cru.ru_utime.tv_sec + 534 k->ki_u.u_cru.ru_stime.tv_sec; 535 psecs += k->ki_u.u_cru.ru_utime.tv_usec + 536 k->ki_u.u_cru.ru_stime.tv_usec; 537 } 538 /* 539 * round and scale to 100's 540 */ 541 psecs = (psecs + 5000) / 10000; 542 secs += psecs / 100; 543 psecs = psecs % 100; 544 } 545 (void)snprintf(obuff, sizeof(obuff), 546 "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); 547 (void)printf("%*s", v->width, obuff); 548 } 549 550 double 551 getpcpu(k) 552 KINFO *k; 553 { 554 struct proc *p; 555 static int failure; 556 557 if (!nlistread) 558 failure = (kd) ? donlist() : 1; 559 if (failure) 560 return (0.0); 561 562 p = KI_PROC(k); 563 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 564 565 /* XXX - I don't like this */ 566 if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0 || 567 P_ZOMBIE(p)) 568 return (0.0); 569 if (rawcpu) 570 return (100.0 * fxtofl(p->p_pctcpu)); 571 return (100.0 * fxtofl(p->p_pctcpu) / 572 (1.0 - exp(p->p_swtime * log(fxtofl(ccpu))))); 573 } 574 575 void 576 pcpu(k, ve) 577 KINFO *k; 578 VARENT *ve; 579 { 580 VAR *v; 581 582 v = ve->var; 583 (void)printf("%*.1f", v->width, getpcpu(k)); 584 } 585 586 double 587 getpmem(k) 588 KINFO *k; 589 { 590 static int failure; 591 struct proc *p; 592 struct eproc *e; 593 double fracmem; 594 int szptudot; 595 596 if (!nlistread) 597 failure = (kd) ? donlist() : 1; 598 if (failure) 599 return (0.0); 600 601 p = KI_PROC(k); 602 e = KI_EPROC(k); 603 if ((p->p_flag & P_INMEM) == 0) 604 return (0.0); 605 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 606 szptudot = USPACE/getpagesize(); 607 /* XXX don't have info about shared */ 608 fracmem = ((float)e->e_vm.vm_rssize + szptudot)/mempages; 609 return (100.0 * fracmem); 610 } 611 612 void 613 pmem(k, ve) 614 KINFO *k; 615 VARENT *ve; 616 { 617 VAR *v; 618 619 v = ve->var; 620 (void)printf("%*.1f", v->width, getpmem(k)); 621 } 622 623 void 624 pagein(k, ve) 625 KINFO *k; 626 VARENT *ve; 627 { 628 VAR *v; 629 630 v = ve->var; 631 (void)printf("%*ld", v->width, 632 k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0); 633 } 634 635 void 636 maxrss(k, ve) 637 KINFO *k; 638 VARENT *ve; 639 { 640 VAR *v; 641 642 v = ve->var; 643 (void)printf("%*s", v->width, "-"); 644 } 645 646 void 647 tsize(k, ve) 648 KINFO *k; 649 VARENT *ve; 650 { 651 VAR *v; 652 653 v = ve->var; 654 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_tsize)); 655 } 656 657 /* 658 * Generic output routines. Print fields from various prototype 659 * structures. 660 */ 661 static void 662 printval(bp, v) 663 char *bp; 664 VAR *v; 665 { 666 static char ofmt[32] = "%"; 667 char *fcp, *cp; 668 enum type type; 669 670 cp = ofmt + 1; 671 fcp = v->fmt; 672 if (v->flag & LJUST) 673 *cp++ = '-'; 674 *cp++ = '*'; 675 while ((*cp++ = *fcp++) != '\0') 676 continue; 677 678 /* 679 * Note that the "INF127" check is nonsensical for types 680 * that are or can be signed. 681 */ 682 #define GET(type) (*(type *)bp) 683 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 684 685 switch (v->type) { 686 case INT32: 687 if (sizeof(int32_t) == sizeof(int)) 688 type = INT; 689 else if (sizeof(int32_t) == sizeof(long)) 690 type = LONG; 691 else 692 errx(1, "unknown conversion for type %d", v->type); 693 break; 694 case UINT32: 695 if (sizeof(u_int32_t) == sizeof(u_int)) 696 type = UINT; 697 else if (sizeof(u_int32_t) == sizeof(u_long)) 698 type = ULONG; 699 else 700 errx(1, "unknown conversion for type %d", v->type); 701 break; 702 default: 703 type = v->type; 704 break; 705 } 706 707 switch (type) { 708 case CHAR: 709 (void)printf(ofmt, v->width, GET(char)); 710 break; 711 case UCHAR: 712 (void)printf(ofmt, v->width, CHK_INF127(GET(u_char))); 713 break; 714 case SHORT: 715 (void)printf(ofmt, v->width, GET(short)); 716 break; 717 case USHORT: 718 (void)printf(ofmt, v->width, CHK_INF127(GET(u_short))); 719 break; 720 case INT: 721 (void)printf(ofmt, v->width, GET(int)); 722 break; 723 case UINT: 724 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int))); 725 break; 726 case LONG: 727 (void)printf(ofmt, v->width, GET(long)); 728 break; 729 case ULONG: 730 (void)printf(ofmt, v->width, CHK_INF127(GET(u_long))); 731 break; 732 case KPTR: 733 (void)printf(ofmt, v->width, GET(u_long)); 734 break; 735 case KPTR24: 736 (void)printf(ofmt, v->width, GET(u_long) & 0xffffff); 737 break; 738 case SIGLIST: 739 { 740 sigset_t *s = (sigset_t *)(void *)bp; 741 size_t i; 742 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 743 char buf[SIGSETSIZE * 8 + 1]; 744 745 for (i = 0; i < SIGSETSIZE; i++) 746 (void)snprintf(&buf[i * 8], 9, "%.8x", 747 s->__bits[(SIGSETSIZE - 1) - i]); 748 749 /* Skip leading zeroes */ 750 for (i = 0; buf[i]; i++) 751 if (buf[i] != '0') 752 break; 753 754 if (buf[i] == '\0') 755 i--; 756 (void)printf(ofmt, v->width, &buf[i]); 757 } 758 break; 759 default: 760 errx(1, "unknown type %d", v->type); 761 } 762 #undef GET 763 #undef CHK_INF127 764 } 765 766 void 767 pvar(k, ve) 768 KINFO *k; 769 VARENT *ve; 770 { 771 VAR *v; 772 773 v = ve->var; 774 printval((char *)KI_PROC(k) + v->off, v); 775 } 776 777 void 778 evar(k, ve) 779 KINFO *k; 780 VARENT *ve; 781 { 782 VAR *v; 783 784 v = ve->var; 785 printval((char *)KI_EPROC(k) + v->off, v); 786 } 787 788 void 789 uvar(k, ve) 790 KINFO *k; 791 VARENT *ve; 792 { 793 VAR *v; 794 795 v = ve->var; 796 if (k->ki_u.u_valid) 797 printval((char *)&k->ki_u + v->off, v); 798 else 799 (void)printf("%*s", v->width, "-"); 800 } 801 802 void 803 rvar(k, ve) 804 KINFO *k; 805 VARENT *ve; 806 { 807 VAR *v; 808 809 v = ve->var; 810 if (k->ki_u.u_valid) 811 printval((char *)&k->ki_u.u_ru + v->off, v); 812 else 813 (void)printf("%*s", v->width, "-"); 814 } 815