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