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