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 __P((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 if (k->ki_p->ki_kiflag & KI_MTXBLOCK) { 413 (void)printf("%-*.*s", v->width, v->width, k->ki_p->ki_mtxname); 414 } else { 415 (void)printf("%-*s", v->width, "-"); 416 } 417 } 418 419 #ifndef pgtok 420 #define pgtok(a) (((a)*getpagesize())/1024) 421 #endif 422 423 void 424 vsize(KINFO *k, VARENT *ve) 425 { 426 VAR *v; 427 428 v = ve->var; 429 (void)printf("%*d", v->width, 430 (k->ki_p->ki_size/1024)); 431 } 432 433 void 434 cputime(KINFO *k, VARENT *ve) 435 { 436 VAR *v; 437 long secs; 438 long psecs; /* "parts" of a second. first micro, then centi */ 439 char obuff[128]; 440 static char decimal_point = 0; 441 442 if (!decimal_point) 443 decimal_point = localeconv()->decimal_point[0]; 444 v = ve->var; 445 if (k->ki_p->ki_stat == SZOMB || !k->ki_valid) { 446 secs = 0; 447 psecs = 0; 448 } else { 449 /* 450 * This counts time spent handling interrupts. We could 451 * fix this, but it is not 100% trivial (and interrupt 452 * time fractions only work on the sparc anyway). XXX 453 */ 454 secs = k->ki_p->ki_runtime / 1000000; 455 psecs = k->ki_p->ki_runtime % 1000000; 456 if (sumrusage) { 457 secs += k->ki_p->ki_childtime.tv_sec; 458 psecs += k->ki_p->ki_childtime.tv_usec; 459 } 460 /* 461 * round and scale to 100's 462 */ 463 psecs = (psecs + 5000) / 10000; 464 secs += psecs / 100; 465 psecs = psecs % 100; 466 } 467 (void)snprintf(obuff, sizeof(obuff), 468 "%3ld:%02ld%c%02ld", secs/60, secs%60, decimal_point, psecs); 469 (void)printf("%*s", v->width, obuff); 470 } 471 472 double 473 getpcpu(const KINFO *k) 474 { 475 static int failure; 476 477 if (!nlistread) 478 failure = donlist(); 479 if (failure) 480 return (0.0); 481 482 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 483 484 /* XXX - I don't like this */ 485 if (k->ki_p->ki_swtime == 0 || (k->ki_p->ki_sflag & PS_INMEM) == 0) 486 return (0.0); 487 if (rawcpu) 488 return (100.0 * fxtofl(k->ki_p->ki_pctcpu)); 489 return (100.0 * fxtofl(k->ki_p->ki_pctcpu) / 490 (1.0 - exp(k->ki_p->ki_swtime * log(fxtofl(ccpu))))); 491 } 492 493 void 494 pcpu(KINFO *k, VARENT *ve) 495 { 496 VAR *v; 497 498 v = ve->var; 499 (void)printf("%*.1f", v->width, getpcpu(k)); 500 } 501 502 static double 503 getpmem(KINFO *k) 504 { 505 static int failure; 506 double fracmem; 507 508 if (!nlistread) 509 failure = donlist(); 510 if (failure) 511 return (0.0); 512 513 if ((k->ki_p->ki_sflag & PS_INMEM) == 0) 514 return (0.0); 515 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 516 /* XXX don't have info about shared */ 517 fracmem = ((float)k->ki_p->ki_rssize)/mempages; 518 return (100.0 * fracmem); 519 } 520 521 void 522 pmem(KINFO *k, VARENT *ve) 523 { 524 VAR *v; 525 526 v = ve->var; 527 (void)printf("%*.1f", v->width, getpmem(k)); 528 } 529 530 void 531 pagein(KINFO *k, VARENT *ve) 532 { 533 VAR *v; 534 535 v = ve->var; 536 (void)printf("%*ld", v->width, 537 k->ki_valid ? k->ki_p->ki_rusage.ru_majflt : 0); 538 } 539 540 /* ARGSUSED */ 541 void 542 maxrss(KINFO *k __unused, VARENT *ve) 543 { 544 VAR *v; 545 546 v = ve->var; 547 /* XXX not yet */ 548 (void)printf("%*s", v->width, "-"); 549 } 550 551 void 552 tsize(KINFO *k, VARENT *ve) 553 { 554 VAR *v; 555 556 v = ve->var; 557 (void)printf("%*ld", v->width, (long)pgtok(k->ki_p->ki_tsize)); 558 } 559 560 void 561 priorityr(KINFO *k, VARENT *ve) 562 { 563 VAR *v; 564 struct priority *lpri; 565 char str[8]; 566 unsigned class, level; 567 568 v = ve->var; 569 lpri = (struct priority *) ((char *)k + v->off); 570 class = lpri->pri_class; 571 level = lpri->pri_level; 572 switch (class) { 573 case PRI_REALTIME: 574 snprintf(str, sizeof(str), "real:%u", level); 575 break; 576 case PRI_TIMESHARE: 577 strncpy(str, "normal", sizeof(str)); 578 break; 579 case PRI_IDLE: 580 snprintf(str, sizeof(str), "idle:%u", level); 581 break; 582 default: 583 snprintf(str, sizeof(str), "%u:%u", class, level); 584 break; 585 } 586 str[sizeof(str) - 1] = '\0'; 587 (void)printf("%*s", v->width, str); 588 } 589 590 /* 591 * Generic output routines. Print fields from various prototype 592 * structures. 593 */ 594 static void 595 printval(char *bp, VAR *v) 596 { 597 static char ofmt[32] = "%"; 598 char *fcp, *cp; 599 600 cp = ofmt + 1; 601 fcp = v->fmt; 602 if (v->flag & LJUST) 603 *cp++ = '-'; 604 *cp++ = '*'; 605 while ((*cp++ = *fcp++)); 606 607 switch (v->type) { 608 case CHAR: 609 (void)printf(ofmt, v->width, *(char *)bp); 610 break; 611 case UCHAR: 612 (void)printf(ofmt, v->width, *(u_char *)bp); 613 break; 614 case SHORT: 615 (void)printf(ofmt, v->width, *(short *)bp); 616 break; 617 case USHORT: 618 (void)printf(ofmt, v->width, *(u_short *)bp); 619 break; 620 case INT: 621 (void)printf(ofmt, v->width, *(int *)bp); 622 break; 623 case UINT: 624 (void)printf(ofmt, v->width, *(u_int *)bp); 625 break; 626 case LONG: 627 (void)printf(ofmt, v->width, *(long *)bp); 628 break; 629 case ULONG: 630 (void)printf(ofmt, v->width, *(u_long *)bp); 631 break; 632 case KPTR: 633 (void)printf(ofmt, v->width, *(u_long *)bp); 634 break; 635 default: 636 errx(1, "unknown type %d", v->type); 637 } 638 } 639 640 void 641 kvar(KINFO *k, VARENT *ve) 642 { 643 VAR *v; 644 645 v = ve->var; 646 printval((char *)((char *)k->ki_p + v->off), v); 647 } 648 649 void 650 rvar(KINFO *k, VARENT *ve) 651 { 652 VAR *v; 653 654 v = ve->var; 655 if (k->ki_valid) 656 printval((char *)((char *)(&k->ki_p->ki_rusage) + v->off), v); 657 else 658 (void)printf("%*s", v->width, "-"); 659 } 660 661 void 662 lattr(KINFO *k, VARENT *ve) 663 { 664 VAR *v; 665 666 v = ve->var; 667 (void)printf("%-*d", (int)v->width, get_lattr(k->ki_p->ki_pid)); 668 } 669