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