1 /* $NetBSD: print.c,v 1.39 1998/07/28 18:41:59 mycroft 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.39 1998/07/28 18:41:59 mycroft 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 extern kvm_t *kd; 71 extern int needenv, needcomm, commandonly; 72 73 static char *cmdpart __P((char *)); 74 static void printval __P((char *, VAR *)); 75 static int titlecmp __P((char *, char **)); 76 77 #define min(a,b) ((a) <= (b) ? (a) : (b)) 78 #define max(a,b) ((a) >= (b) ? (a) : (b)) 79 80 static char * 81 cmdpart(arg0) 82 char *arg0; 83 { 84 char *cp; 85 86 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 87 } 88 89 void 90 printheader() 91 { 92 VAR *v; 93 struct varent *vent; 94 95 for (vent = vhead; vent; vent = vent->next) { 96 v = vent->var; 97 if (v->flag & LJUST) { 98 if (vent->next == NULL) /* last one */ 99 (void)printf("%s", v->header); 100 else 101 (void)printf("%-*s", v->width, v->header); 102 } else 103 (void)printf("%*s", v->width, v->header); 104 if (vent->next != NULL) 105 (void)putchar(' '); 106 } 107 (void)putchar('\n'); 108 } 109 110 static int 111 titlecmp(name, argv) 112 char *name; 113 char **argv; 114 { 115 char *title; 116 int namelen; 117 118 if (argv == 0 || argv[0] == 0) 119 return (1); 120 121 title = cmdpart(argv[0]); 122 123 if (!strcmp(name, title)) 124 return (0); 125 126 if (title[0] == '-' && !strcmp(name, title+1)) 127 return (0); 128 129 namelen = strlen(name); 130 131 if (argv[1] == 0 && 132 !strncmp(name, title, namelen) && 133 title[namelen+0] == ':' && 134 title[namelen+1] == ' ') 135 return (0); 136 137 return (1); 138 } 139 140 void 141 command(ki, ve) 142 KINFO *ki; 143 VARENT *ve; 144 { 145 VAR *v; 146 int left; 147 char **argv, **p, *name; 148 149 v = ve->var; 150 if (ve->next != NULL || termwidth != UNLIMITED) { 151 if (ve->next == NULL) { 152 left = termwidth - (totwidth - v->width); 153 if (left < 1) /* already wrapped, just use std width */ 154 left = v->width; 155 } else 156 left = v->width; 157 } else 158 left = -1; 159 if (needenv) { 160 argv = kvm_getenvv(kd, ki->ki_p, termwidth); 161 if ((p = argv) != NULL) { 162 while (*p) { 163 fmt_puts(*p, &left); 164 p++; 165 fmt_putc(' ', &left); 166 } 167 } 168 } 169 if (needcomm) { 170 name = KI_PROC(ki)->p_comm; 171 if (!commandonly) { 172 argv = kvm_getargv(kd, ki->ki_p, termwidth); 173 if ((p = argv) != NULL) { 174 while (*p) { 175 fmt_puts(*p, &left); 176 p++; 177 fmt_putc(' ', &left); 178 } 179 } 180 if (titlecmp(name, argv)) { 181 fmt_putc('(', &left); 182 fmt_puts(name, &left); 183 fmt_putc(')', &left); 184 } 185 } else { 186 fmt_puts(name, &left); 187 } 188 } 189 if (ve->next && left > 0) 190 printf("%*s", left, ""); 191 } 192 193 void 194 ucomm(k, ve) 195 KINFO *k; 196 VARENT *ve; 197 { 198 VAR *v; 199 200 v = ve->var; 201 (void)printf("%-*s", v->width, KI_PROC(k)->p_comm); 202 } 203 204 void 205 logname(k, ve) 206 KINFO *k; 207 VARENT *ve; 208 { 209 VAR *v; 210 int n; 211 212 v = ve->var; 213 n = min(v->width, MAXLOGNAME); 214 (void)printf("%-*.*s", n, n, KI_EPROC(k)->e_login); 215 if (v->width > n) 216 (void)printf("%*s", v->width - n, ""); 217 } 218 219 void 220 state(k, ve) 221 KINFO *k; 222 VARENT *ve; 223 { 224 struct proc *p; 225 int flag; 226 char *cp; 227 VAR *v; 228 char buf[16]; 229 230 v = ve->var; 231 p = KI_PROC(k); 232 flag = p->p_flag; 233 cp = buf; 234 235 switch (p->p_stat) { 236 237 case SSTOP: 238 *cp = 'T'; 239 break; 240 241 case SSLEEP: 242 if (flag & P_SINTR) /* interuptable (long) */ 243 *cp = p->p_slptime >= MAXSLP ? 'I' : 'S'; 244 else 245 *cp = 'D'; 246 break; 247 248 case SRUN: 249 case SIDL: 250 *cp = 'R'; 251 break; 252 253 case SZOMB: 254 *cp = 'Z'; 255 break; 256 257 default: 258 *cp = '?'; 259 } 260 cp++; 261 if (flag & P_INMEM) { 262 } else 263 *cp++ = 'W'; 264 if (p->p_nice < NZERO) 265 *cp++ = '<'; 266 else if (p->p_nice > NZERO) 267 *cp++ = 'N'; 268 if (flag & P_TRACED) 269 *cp++ = 'X'; 270 if (flag & P_WEXIT && p->p_stat != SZOMB) 271 *cp++ = 'E'; 272 if (flag & P_PPWAIT) 273 *cp++ = 'V'; 274 if ((flag & P_SYSTEM) || p->p_holdcnt) 275 *cp++ = 'L'; 276 if (KI_EPROC(k)->e_flag & EPROC_SLEADER) 277 *cp++ = 's'; 278 if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid) 279 *cp++ = '+'; 280 *cp = '\0'; 281 (void)printf("%-*s", v->width, buf); 282 } 283 284 void 285 pnice(k, ve) 286 KINFO *k; 287 VARENT *ve; 288 { 289 VAR *v; 290 291 v = ve->var; 292 (void)printf("%*d", v->width, KI_PROC(k)->p_nice - NZERO); 293 } 294 295 void 296 pri(k, ve) 297 KINFO *k; 298 VARENT *ve; 299 { 300 VAR *v; 301 302 v = ve->var; 303 (void)printf("%*d", v->width, KI_PROC(k)->p_priority - PZERO); 304 } 305 306 void 307 uname(k, ve) 308 KINFO *k; 309 VARENT *ve; 310 { 311 VAR *v; 312 313 v = ve->var; 314 (void)printf("%-*s", 315 (int)v->width, user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)); 316 } 317 318 void 319 runame(k, ve) 320 KINFO *k; 321 VARENT *ve; 322 { 323 VAR *v; 324 325 v = ve->var; 326 (void)printf("%-*s", 327 (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0)); 328 } 329 330 void 331 tdev(k, ve) 332 KINFO *k; 333 VARENT *ve; 334 { 335 VAR *v; 336 dev_t dev; 337 char buff[16]; 338 339 v = ve->var; 340 dev = KI_EPROC(k)->e_tdev; 341 if (dev == NODEV) 342 (void)printf("%*s", v->width, "??"); 343 else { 344 (void)snprintf(buff, sizeof(buff), 345 "%d/%d", major(dev), minor(dev)); 346 (void)printf("%*s", v->width, buff); 347 } 348 } 349 350 void 351 tname(k, ve) 352 KINFO *k; 353 VARENT *ve; 354 { 355 VAR *v; 356 dev_t dev; 357 const char *ttname; 358 359 v = ve->var; 360 dev = KI_EPROC(k)->e_tdev; 361 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 362 (void)printf("%-*s", v->width, "??"); 363 else { 364 if (strncmp(ttname, "tty", 3) == 0) 365 ttname += 3; 366 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, 367 KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-'); 368 } 369 } 370 371 void 372 longtname(k, ve) 373 KINFO *k; 374 VARENT *ve; 375 { 376 VAR *v; 377 dev_t dev; 378 const char *ttname; 379 380 v = ve->var; 381 dev = KI_EPROC(k)->e_tdev; 382 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 383 (void)printf("%-*s", v->width, "??"); 384 else 385 (void)printf("%-*s", v->width, ttname); 386 } 387 388 void 389 started(k, ve) 390 KINFO *k; 391 VARENT *ve; 392 { 393 VAR *v; 394 static time_t now; 395 time_t startt; 396 struct tm *tp; 397 char buf[100]; 398 399 v = ve->var; 400 if (!k->ki_u.u_valid) { 401 (void)printf("%-*s", v->width, "-"); 402 return; 403 } 404 405 startt = k->ki_u.u_start.tv_sec; 406 tp = localtime(&startt); 407 if (!now) 408 (void)time(&now); 409 if (now - k->ki_u.u_start.tv_sec < 24 * SECSPERHOUR) { 410 /* I *hate* SCCS... */ 411 static char fmt[] = __CONCAT("%l:%", "M%p"); 412 (void)strftime(buf, sizeof(buf) - 1, fmt, tp); 413 } else if (now - k->ki_u.u_start.tv_sec < 7 * SECSPERDAY) { 414 /* I *hate* SCCS... */ 415 static char fmt[] = __CONCAT("%a%", "I%p"); 416 (void)strftime(buf, sizeof(buf) - 1, fmt, tp); 417 } else 418 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 419 (void)printf("%-*s", v->width, buf); 420 } 421 422 void 423 lstarted(k, ve) 424 KINFO *k; 425 VARENT *ve; 426 { 427 VAR *v; 428 time_t startt; 429 char buf[100]; 430 431 v = ve->var; 432 if (!k->ki_u.u_valid) { 433 (void)printf("%-*s", v->width, "-"); 434 return; 435 } 436 startt = k->ki_u.u_start.tv_sec; 437 (void)strftime(buf, sizeof(buf) -1, "%c", 438 localtime(&startt)); 439 (void)printf("%-*s", v->width, buf); 440 } 441 442 void 443 wchan(k, ve) 444 KINFO *k; 445 VARENT *ve; 446 { 447 VAR *v; 448 int n; 449 450 v = ve->var; 451 if (KI_PROC(k)->p_wchan) { 452 if (KI_PROC(k)->p_wmesg) { 453 n = min(v->width, WMESGLEN); 454 (void)printf("%-*.*s", n, n, KI_EPROC(k)->e_wmesg); 455 if (v->width > n) 456 (void)printf("%*s", v->width - n, ""); 457 } else 458 (void)printf("%-*lx", v->width, 459 (long)KI_PROC(k)->p_wchan); 460 } else 461 (void)printf("%-*s", v->width, "-"); 462 } 463 464 #define pgtok(a) (((a)*getpagesize())/1024) 465 466 void 467 vsize(k, ve) 468 KINFO *k; 469 VARENT *ve; 470 { 471 VAR *v; 472 473 v = ve->var; 474 (void)printf("%*d", v->width, 475 pgtok(KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + 476 KI_EPROC(k)->e_vm.vm_tsize)); 477 } 478 479 void 480 rssize(k, ve) 481 KINFO *k; 482 VARENT *ve; 483 { 484 VAR *v; 485 486 v = ve->var; 487 /* XXX don't have info about shared */ 488 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize)); 489 } 490 491 void 492 p_rssize(k, ve) /* doesn't account for text */ 493 KINFO *k; 494 VARENT *ve; 495 { 496 VAR *v; 497 498 v = ve->var; 499 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize)); 500 } 501 502 void 503 cputime(k, ve) 504 KINFO *k; 505 VARENT *ve; 506 { 507 VAR *v; 508 long secs; 509 long psecs; /* "parts" of a second. first micro, then centi */ 510 char obuff[128]; 511 512 v = ve->var; 513 if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) { 514 secs = 0; 515 psecs = 0; 516 } else { 517 /* 518 * This counts time spent handling interrupts. We could 519 * fix this, but it is not 100% trivial (and interrupt 520 * time fractions only work on the sparc anyway). XXX 521 */ 522 secs = KI_PROC(k)->p_rtime.tv_sec; 523 psecs = KI_PROC(k)->p_rtime.tv_usec; 524 if (sumrusage) { 525 secs += k->ki_u.u_cru.ru_utime.tv_sec + 526 k->ki_u.u_cru.ru_stime.tv_sec; 527 psecs += k->ki_u.u_cru.ru_utime.tv_usec + 528 k->ki_u.u_cru.ru_stime.tv_usec; 529 } 530 /* 531 * round and scale to 100's 532 */ 533 psecs = (psecs + 5000) / 10000; 534 secs += psecs / 100; 535 psecs = psecs % 100; 536 } 537 (void)snprintf(obuff, sizeof(obuff), 538 "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); 539 (void)printf("%*s", v->width, obuff); 540 } 541 542 double 543 getpcpu(k) 544 KINFO *k; 545 { 546 struct proc *p; 547 static int failure; 548 549 if (!nlistread) 550 failure = donlist(); 551 if (failure) 552 return (0.0); 553 554 p = KI_PROC(k); 555 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 556 557 /* XXX - I don't like this */ 558 if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0 559 || p->p_stat == SZOMB) 560 return (0.0); 561 if (rawcpu) 562 return (100.0 * fxtofl(p->p_pctcpu)); 563 return (100.0 * fxtofl(p->p_pctcpu) / 564 (1.0 - exp(p->p_swtime * log(fxtofl(ccpu))))); 565 } 566 567 void 568 pcpu(k, ve) 569 KINFO *k; 570 VARENT *ve; 571 { 572 VAR *v; 573 574 v = ve->var; 575 (void)printf("%*.1f", v->width, getpcpu(k)); 576 } 577 578 double 579 getpmem(k) 580 KINFO *k; 581 { 582 static int failure; 583 struct proc *p; 584 struct eproc *e; 585 double fracmem; 586 int szptudot; 587 588 if (!nlistread) 589 failure = donlist(); 590 if (failure) 591 return (0.0); 592 593 p = KI_PROC(k); 594 e = KI_EPROC(k); 595 if ((p->p_flag & P_INMEM) == 0) 596 return (0.0); 597 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 598 szptudot = USPACE/getpagesize(); 599 /* XXX don't have info about shared */ 600 fracmem = ((float)e->e_vm.vm_rssize + szptudot)/CLSIZE/mempages; 601 return (100.0 * fracmem); 602 } 603 604 void 605 pmem(k, ve) 606 KINFO *k; 607 VARENT *ve; 608 { 609 VAR *v; 610 611 v = ve->var; 612 (void)printf("%*.1f", v->width, getpmem(k)); 613 } 614 615 void 616 pagein(k, ve) 617 KINFO *k; 618 VARENT *ve; 619 { 620 VAR *v; 621 622 v = ve->var; 623 (void)printf("%*ld", v->width, 624 k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0); 625 } 626 627 void 628 maxrss(k, ve) 629 KINFO *k; 630 VARENT *ve; 631 { 632 VAR *v; 633 634 v = ve->var; 635 (void)printf("%*s", v->width, "-"); 636 } 637 638 void 639 tsize(k, ve) 640 KINFO *k; 641 VARENT *ve; 642 { 643 VAR *v; 644 645 v = ve->var; 646 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_tsize)); 647 } 648 649 /* 650 * Generic output routines. Print fields from various prototype 651 * structures. 652 */ 653 static void 654 printval(bp, v) 655 char *bp; 656 VAR *v; 657 { 658 static char ofmt[32] = "%"; 659 char *fcp, *cp; 660 enum type type; 661 662 cp = ofmt + 1; 663 fcp = v->fmt; 664 if (v->flag & LJUST) 665 *cp++ = '-'; 666 *cp++ = '*'; 667 while ((*cp++ = *fcp++) != '\0') 668 continue; 669 670 /* 671 * Note that the "INF127" check is nonsensical for types 672 * that are or can be signed. 673 */ 674 #define GET(type) (*(type *)bp) 675 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 676 677 switch (v->type) { 678 case INT32: 679 if (sizeof(int32_t) == sizeof(int)) 680 type = INT; 681 else if (sizeof(int32_t) == sizeof(long)) 682 type = LONG; 683 else 684 errx(1, "unknown conversion for type %d", v->type); 685 break; 686 case UINT32: 687 if (sizeof(u_int32_t) == sizeof(u_int)) 688 type = UINT; 689 else if (sizeof(u_int32_t) == sizeof(u_long)) 690 type = ULONG; 691 else 692 errx(1, "unknown conversion for type %d", v->type); 693 break; 694 default: 695 type = v->type; 696 break; 697 } 698 699 switch (type) { 700 case CHAR: 701 (void)printf(ofmt, v->width, GET(char)); 702 break; 703 case UCHAR: 704 (void)printf(ofmt, v->width, CHK_INF127(GET(u_char))); 705 break; 706 case SHORT: 707 (void)printf(ofmt, v->width, GET(short)); 708 break; 709 case USHORT: 710 (void)printf(ofmt, v->width, CHK_INF127(GET(u_short))); 711 break; 712 case INT: 713 (void)printf(ofmt, v->width, GET(int)); 714 break; 715 case UINT: 716 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int))); 717 break; 718 case LONG: 719 (void)printf(ofmt, v->width, GET(long)); 720 break; 721 case ULONG: 722 (void)printf(ofmt, v->width, CHK_INF127(GET(u_long))); 723 break; 724 case KPTR: 725 (void)printf(ofmt, v->width, GET(u_long)); 726 break; 727 default: 728 errx(1, "unknown type %d", v->type); 729 } 730 #undef GET 731 #undef CHK_INF127 732 } 733 734 void 735 pvar(k, ve) 736 KINFO *k; 737 VARENT *ve; 738 { 739 VAR *v; 740 741 v = ve->var; 742 printval((char *)KI_PROC(k) + v->off, v); 743 } 744 745 void 746 evar(k, ve) 747 KINFO *k; 748 VARENT *ve; 749 { 750 VAR *v; 751 752 v = ve->var; 753 printval((char *)KI_EPROC(k) + v->off, v); 754 } 755 756 void 757 uvar(k, ve) 758 KINFO *k; 759 VARENT *ve; 760 { 761 VAR *v; 762 763 v = ve->var; 764 if (k->ki_u.u_valid) 765 printval((char *)&k->ki_u + v->off, v); 766 else 767 (void)printf("%*s", v->width, "-"); 768 } 769 770 void 771 rvar(k, ve) 772 KINFO *k; 773 VARENT *ve; 774 { 775 VAR *v; 776 777 v = ve->var; 778 if (k->ki_u.u_valid) 779 printval((char *)&k->ki_u.u_ru + v->off, v); 780 else 781 (void)printf("%*s", v->width, "-"); 782 } 783