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