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