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