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