1 /* $NetBSD: print.c,v 1.52 2000/06/02 03:39:02 simonb 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.52 2000/06/02 03:39:02 simonb 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 struct kinfo_proc2 *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 && kd) { 157 argv = kvm_getenvv2(kd, ki, termwidth); 158 if ((p = argv) != NULL) { 159 while (*p) { 160 fmt_puts(*p, &left); 161 p++; 162 fmt_putc(' ', &left); 163 } 164 } 165 } 166 if (needcomm) { 167 name = ki->p_comm; 168 if (!commandonly) { 169 argv = NULL; 170 if (!use_procfs) 171 argv = kvm_getargv2(kd, ki, termwidth); 172 else 173 argv = procfs_getargv(ki, termwidth); 174 if ((p = argv) != NULL) { 175 while (*p) { 176 fmt_puts(*p, &left); 177 p++; 178 fmt_putc(' ', &left); 179 } 180 } 181 if (titlecmp(name, argv)) { 182 fmt_putc('(', &left); 183 fmt_puts(name, &left); 184 fmt_putc(')', &left); 185 } 186 if (use_procfs && argv) { 187 free(argv[0]); 188 free(argv); 189 } 190 } else { 191 fmt_puts(name, &left); 192 } 193 } 194 if (ve->next && left > 0) 195 printf("%*s", left, ""); 196 } 197 198 void 199 ucomm(k, ve) 200 struct kinfo_proc2 *k; 201 VARENT *ve; 202 { 203 VAR *v; 204 205 v = ve->var; 206 (void)printf("%-*s", v->width, k->p_comm); 207 } 208 209 void 210 logname(k, ve) 211 struct kinfo_proc2 *k; 212 VARENT *ve; 213 { 214 VAR *v; 215 int n; 216 217 v = ve->var; 218 n = min(v->width, MAXLOGNAME); 219 (void)printf("%-*.*s", n, n, k->p_login); 220 if (v->width > n) 221 (void)printf("%*s", v->width - n, ""); 222 } 223 224 void 225 state(k, ve) 226 struct kinfo_proc2 *k; 227 VARENT *ve; 228 { 229 int flag, is_zombie; 230 char *cp; 231 VAR *v; 232 char buf[16]; 233 234 is_zombie = 0; 235 v = ve->var; 236 flag = k->p_flag; 237 cp = buf; 238 239 switch (k->p_stat) { 240 241 case SSTOP: 242 *cp = 'T'; 243 break; 244 245 case SSLEEP: 246 if (flag & P_SINTR) /* interuptable (long) */ 247 *cp = k->p_slptime >= MAXSLP ? 'I' : 'S'; 248 else 249 *cp = 'D'; 250 break; 251 252 case SRUN: 253 case SIDL: 254 case SONPROC: 255 *cp = 'R'; 256 break; 257 258 case SZOMB: 259 case SDEAD: 260 *cp = 'Z'; 261 is_zombie = 1; 262 break; 263 264 default: 265 *cp = '?'; 266 } 267 cp++; 268 if (flag & P_INMEM) { 269 } else 270 *cp++ = 'W'; 271 if (k->p_nice < NZERO) 272 *cp++ = '<'; 273 else if (k->p_nice > NZERO) 274 *cp++ = 'N'; 275 if (flag & P_TRACED) 276 *cp++ = 'X'; 277 if (flag & P_WEXIT && !is_zombie) 278 *cp++ = 'E'; 279 if (flag & P_PPWAIT) 280 *cp++ = 'V'; 281 if ((flag & P_SYSTEM) || k->p_holdcnt) 282 *cp++ = 'L'; 283 if (k->p_eflag & EPROC_SLEADER) 284 *cp++ = 's'; 285 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid) 286 *cp++ = '+'; 287 *cp = '\0'; 288 (void)printf("%-*s", v->width, buf); 289 } 290 291 void 292 pnice(k, ve) 293 struct kinfo_proc2 *k; 294 VARENT *ve; 295 { 296 VAR *v; 297 298 v = ve->var; 299 (void)printf("%*d", v->width, k->p_nice - NZERO); 300 } 301 302 void 303 pri(k, ve) 304 struct kinfo_proc2 *k; 305 VARENT *ve; 306 { 307 VAR *v; 308 309 v = ve->var; 310 (void)printf("%*d", v->width, k->p_priority - PZERO); 311 } 312 313 void 314 uname(k, ve) 315 struct kinfo_proc2 *k; 316 VARENT *ve; 317 { 318 VAR *v; 319 320 v = ve->var; 321 (void)printf("%-*s", 322 (int)v->width, user_from_uid(k->p_uid, 0)); 323 } 324 325 void 326 runame(k, ve) 327 struct kinfo_proc2 *k; 328 VARENT *ve; 329 { 330 VAR *v; 331 332 v = ve->var; 333 (void)printf("%-*s", 334 (int)v->width, user_from_uid(k->p_ruid, 0)); 335 } 336 337 void 338 tdev(k, ve) 339 struct kinfo_proc2 *k; 340 VARENT *ve; 341 { 342 VAR *v; 343 dev_t dev; 344 char buff[16]; 345 346 v = ve->var; 347 dev = k->p_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 struct kinfo_proc2 *k; 360 VARENT *ve; 361 { 362 VAR *v; 363 dev_t dev; 364 const char *ttname; 365 366 v = ve->var; 367 dev = k->p_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 k->p_eflag & EPROC_CTTY ? ' ' : '-'); 376 } 377 } 378 379 void 380 longtname(k, ve) 381 struct kinfo_proc2 *k; 382 VARENT *ve; 383 { 384 VAR *v; 385 dev_t dev; 386 const char *ttname; 387 388 v = ve->var; 389 dev = k->p_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 struct kinfo_proc2 *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->p_uvalid) { 409 (void)printf("%-*s", v->width, "-"); 410 return; 411 } 412 413 startt = k->p_ustart_sec; 414 tp = localtime(&startt); 415 if (!now) 416 (void)time(&now); 417 if (now - k->p_ustart_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->p_ustart_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 struct kinfo_proc2 *k; 433 VARENT *ve; 434 { 435 VAR *v; 436 time_t startt; 437 char buf[100]; 438 439 v = ve->var; 440 if (!k->p_uvalid) { 441 (void)printf("%-*s", v->width, "-"); 442 return; 443 } 444 startt = k->p_ustart_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 struct kinfo_proc2 *k; 453 VARENT *ve; 454 { 455 VAR *v; 456 int n; 457 458 v = ve->var; 459 if (k->p_wchan) { 460 if (k->p_wmesg) { 461 n = min(v->width, WMESGLEN); 462 (void)printf("%-*.*s", n, n, k->p_wmesg); 463 if (v->width > n) 464 (void)printf("%*s", v->width - n, ""); 465 } else 466 (void)printf("%-*lx", v->width, 467 (long)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 struct kinfo_proc2 *k; 477 VARENT *ve; 478 { 479 VAR *v; 480 481 v = ve->var; 482 (void)printf("%*d", v->width, 483 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize)); 484 } 485 486 void 487 rssize(k, ve) 488 struct kinfo_proc2 *k; 489 VARENT *ve; 490 { 491 VAR *v; 492 493 v = ve->var; 494 /* XXX don't have info about shared */ 495 (void)printf("%*d", v->width, pgtok(k->p_vm_rssize)); 496 } 497 498 void 499 p_rssize(k, ve) /* doesn't account for text */ 500 struct kinfo_proc2 *k; 501 VARENT *ve; 502 { 503 VAR *v; 504 505 v = ve->var; 506 (void)printf("%*d", v->width, pgtok(k->p_vm_rssize)); 507 } 508 509 void 510 cputime(k, ve) 511 struct kinfo_proc2 *k; 512 VARENT *ve; 513 { 514 VAR *v; 515 long secs; 516 long psecs; /* "parts" of a second. first micro, then centi */ 517 char obuff[128]; 518 519 v = ve->var; 520 if (P_ZOMBIE(k) || k->p_uvalid == 0) { 521 secs = 0; 522 psecs = 0; 523 } else { 524 /* 525 * This counts time spent handling interrupts. We could 526 * fix this, but it is not 100% trivial (and interrupt 527 * time fractions only work on the sparc anyway). XXX 528 */ 529 secs = k->p_rtime_sec; 530 psecs = k->p_rtime_usec; 531 if (sumrusage) { 532 secs += k->p_uctime_sec; 533 psecs += k->p_uctime_usec; 534 } 535 /* 536 * round and scale to 100's 537 */ 538 psecs = (psecs + 5000) / 10000; 539 secs += psecs / 100; 540 psecs = psecs % 100; 541 } 542 (void)snprintf(obuff, sizeof(obuff), 543 "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); 544 (void)printf("%*s", v->width, obuff); 545 } 546 547 double 548 getpcpu(k) 549 struct kinfo_proc2 *k; 550 { 551 static int failure; 552 553 if (!nlistread) 554 failure = (kd) ? donlist() : 1; 555 if (failure) 556 return (0.0); 557 558 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 559 560 /* XXX - I don't like this */ 561 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 || 562 k->p_stat == SZOMB || k->p_stat == SDEAD) 563 return (0.0); 564 if (rawcpu) 565 return (100.0 * fxtofl(k->p_pctcpu)); 566 return (100.0 * fxtofl(k->p_pctcpu) / 567 (1.0 - exp(k->p_swtime * log(ccpu)))); 568 } 569 570 void 571 pcpu(k, ve) 572 struct kinfo_proc2 *k; 573 VARENT *ve; 574 { 575 VAR *v; 576 577 v = ve->var; 578 (void)printf("%*.1f", v->width, getpcpu(k)); 579 } 580 581 double 582 getpmem(k) 583 struct kinfo_proc2 *k; 584 { 585 static int failure; 586 double fracmem; 587 int szptudot; 588 589 if (!nlistread) 590 failure = (kd) ? donlist() : 1; 591 if (failure) 592 return (0.0); 593 594 if ((k->p_flag & P_INMEM) == 0) 595 return (0.0); 596 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 597 szptudot = USPACE/getpagesize(); 598 /* XXX don't have info about shared */ 599 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 600 return (100.0 * fracmem); 601 } 602 603 void 604 pmem(k, ve) 605 struct kinfo_proc2 *k; 606 VARENT *ve; 607 { 608 VAR *v; 609 610 v = ve->var; 611 (void)printf("%*.1f", v->width, getpmem(k)); 612 } 613 614 void 615 pagein(k, ve) 616 struct kinfo_proc2 *k; 617 VARENT *ve; 618 { 619 VAR *v; 620 621 v = ve->var; 622 (void)printf("%*lld", v->width, 623 k->p_uvalid ? (long long)k->p_uru_majflt : 0); 624 } 625 626 void 627 maxrss(k, ve) 628 struct kinfo_proc2 *k; 629 VARENT *ve; 630 { 631 VAR *v; 632 633 v = ve->var; 634 (void)printf("%*s", v->width, "-"); 635 } 636 637 void 638 tsize(k, ve) 639 struct kinfo_proc2 *k; 640 VARENT *ve; 641 { 642 VAR *v; 643 644 v = ve->var; 645 (void)printf("%*d", v->width, pgtok(k->p_vm_tsize)); 646 } 647 648 /* 649 * Generic output routines. Print fields from various prototype 650 * structures. 651 */ 652 static void 653 printval(bp, v) 654 char *bp; 655 VAR *v; 656 { 657 static char ofmt[32] = "%"; 658 char *fcp, *cp; 659 enum type type; 660 661 cp = ofmt + 1; 662 fcp = v->fmt; 663 if (v->flag & LJUST) 664 *cp++ = '-'; 665 *cp++ = '*'; 666 while ((*cp++ = *fcp++) != '\0') 667 continue; 668 669 /* 670 * Note that the "INF127" check is nonsensical for types 671 * that are or can be signed. 672 */ 673 #define GET(type) (*(type *)bp) 674 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 675 676 switch (v->type) { 677 case INT32: 678 if (sizeof(int32_t) == sizeof(int)) 679 type = INT; 680 else if (sizeof(int32_t) == sizeof(long)) 681 type = LONG; 682 else 683 errx(1, "unknown conversion for type %d", v->type); 684 break; 685 case UINT32: 686 if (sizeof(u_int32_t) == sizeof(u_int)) 687 type = UINT; 688 else if (sizeof(u_int32_t) == sizeof(u_long)) 689 type = ULONG; 690 else 691 errx(1, "unknown conversion for type %d", v->type); 692 break; 693 default: 694 type = v->type; 695 break; 696 } 697 698 switch (type) { 699 case CHAR: 700 (void)printf(ofmt, v->width, GET(char)); 701 break; 702 case UCHAR: 703 (void)printf(ofmt, v->width, CHK_INF127(GET(u_char))); 704 break; 705 case SHORT: 706 (void)printf(ofmt, v->width, GET(short)); 707 break; 708 case USHORT: 709 (void)printf(ofmt, v->width, CHK_INF127(GET(u_short))); 710 break; 711 case INT: 712 (void)printf(ofmt, v->width, GET(int)); 713 break; 714 case UINT: 715 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int))); 716 break; 717 case LONG: 718 (void)printf(ofmt, v->width, GET(long)); 719 break; 720 case ULONG: 721 (void)printf(ofmt, v->width, CHK_INF127(GET(u_long))); 722 break; 723 case KPTR: 724 (void)printf(ofmt, v->width, GET(u_long)); 725 break; 726 case KPTR24: 727 (void)printf(ofmt, v->width, GET(u_long) & 0xffffff); 728 break; 729 case SIGLIST: 730 { 731 sigset_t *s = (sigset_t *)(void *)bp; 732 size_t i; 733 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 734 char buf[SIGSETSIZE * 8 + 1]; 735 736 for (i = 0; i < SIGSETSIZE; i++) 737 (void)snprintf(&buf[i * 8], 9, "%.8x", 738 s->__bits[(SIGSETSIZE - 1) - i]); 739 740 /* Skip leading zeroes */ 741 for (i = 0; buf[i]; i++) 742 if (buf[i] != '0') 743 break; 744 745 if (buf[i] == '\0') 746 i--; 747 (void)printf(ofmt, v->width, &buf[i]); 748 } 749 break; 750 default: 751 errx(1, "unknown type %d", v->type); 752 } 753 #undef GET 754 #undef CHK_INF127 755 } 756 757 void 758 pvar(k, ve) 759 struct kinfo_proc2 *k; 760 VARENT *ve; 761 { 762 VAR *v; 763 764 v = ve->var; 765 printval((char *)k + v->off, v); 766 } 767