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