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