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