1 /* $OpenBSD: print.c,v 1.44 2008/03/08 19:20:12 millert Exp $ */ 2 /* $NetBSD: print.c,v 1.27 1995/09/29 21:58:12 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1990, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; 36 #else 37 static char rcsid[] = "$OpenBSD: print.c,v 1.44 2008/03/08 19:20:12 millert Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/time.h> 43 #include <sys/resource.h> 44 #include <sys/proc.h> 45 #include <sys/stat.h> 46 47 #include <sys/ucred.h> 48 #include <sys/sysctl.h> 49 #include <uvm/uvm_extern.h> 50 51 #include <err.h> 52 #include <grp.h> 53 #include <kvm.h> 54 #include <math.h> 55 #include <nlist.h> 56 #include <stddef.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <tzfile.h> 61 #include <unistd.h> 62 #include <pwd.h> 63 64 #include "ps.h" 65 66 extern kvm_t *kd; 67 extern int needenv, needcomm, neednlist, commandonly; 68 69 static char *cmdpart(char *); 70 71 #define min(a,b) ((a) < (b) ? (a) : (b)) 72 73 static char * 74 cmdpart(char *arg0) 75 { 76 char *cp; 77 78 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 79 } 80 81 void 82 printheader(void) 83 { 84 VAR *v; 85 struct varent *vent; 86 87 for (vent = vhead; vent; vent = vent->next) { 88 v = vent->var; 89 if (v->flag & LJUST) { 90 if (vent->next == NULL) /* last one */ 91 (void)printf("%s", v->header); 92 else 93 (void)printf("%-*s", v->width, v->header); 94 } else 95 (void)printf("%*s", v->width, v->header); 96 if (vent->next != NULL) 97 (void)putchar(' '); 98 } 99 (void)putchar('\n'); 100 } 101 102 void 103 command(const struct kinfo_proc2 *kp, VARENT *ve) 104 { 105 VAR *v; 106 int left, wantspace = 0; 107 char **argv, **p; 108 109 v = ve->var; 110 if (ve->next != NULL || termwidth != UNLIMITED) { 111 if (ve->next == NULL) { 112 left = termwidth - (totwidth - v->width); 113 if (left < 1) /* already wrapped, just use std width */ 114 left = v->width; 115 } else 116 left = v->width; 117 } else 118 left = -1; 119 if (needenv && kd != NULL) { 120 argv = kvm_getenvv2(kd, kp, termwidth); 121 if ((p = argv) != NULL) { 122 while (*p) { 123 fmt_puts(*p, &left); 124 p++; 125 if (*p) 126 fmt_putc(' ', &left); 127 else 128 wantspace = 1; 129 } 130 } 131 } else 132 argv = NULL; 133 if (needcomm) { 134 if (!commandonly) { 135 if (kd != NULL) { 136 argv = kvm_getargv2(kd, kp, termwidth); 137 if ((p = argv) != NULL) { 138 if (wantspace) { 139 fmt_putc(' ', &left); 140 wantspace = 0; 141 } 142 while (*p) { 143 fmt_puts(*p, &left); 144 p++; 145 if (*p) 146 fmt_putc(' ', &left); 147 else 148 wantspace = 1; 149 } 150 } 151 } 152 if (argv == NULL || argv[0] == '\0' || 153 strcmp(cmdpart(argv[0]), kp->p_comm)) { 154 if (wantspace) { 155 fmt_putc(' ', &left); 156 wantspace = 0; 157 } 158 fmt_putc('(', &left); 159 fmt_puts(kp->p_comm, &left); 160 fmt_putc(')', &left); 161 } 162 } else { 163 if (wantspace) { 164 fmt_putc(' ', &left); 165 wantspace = 0; 166 } 167 fmt_puts(kp->p_comm, &left); 168 } 169 } 170 if (ve->next && left > 0) { 171 if (wantspace) { 172 fmt_putc(' ', &left); 173 wantspace = 0; 174 } 175 printf("%*s", left, ""); 176 } 177 } 178 179 void 180 ucomm(const struct kinfo_proc2 *kp, VARENT *ve) 181 { 182 VAR *v; 183 184 v = ve->var; 185 (void)printf("%-*s", v->width, kp->p_comm); 186 } 187 188 void 189 logname(const struct kinfo_proc2 *kp, VARENT *ve) 190 { 191 VAR *v; 192 193 v = ve->var; 194 if (kp->p_login[0]) { 195 int n = min(v->width, MAXLOGNAME); 196 (void)printf("%-*.*s", n, n, kp->p_login); 197 if (v->width > n) 198 (void)printf("%*s", v->width - n, ""); 199 } else 200 (void)printf("%-*s", v->width, "-"); 201 } 202 203 #define pgtok(a) (((a)*getpagesize())/1024) 204 205 void 206 state(const struct kinfo_proc2 *kp, VARENT *ve) 207 { 208 extern int ncpu; 209 int flag; 210 char *cp, state = '\0'; 211 VAR *v; 212 char buf[16]; 213 214 v = ve->var; 215 flag = kp->p_flag; 216 cp = buf; 217 218 switch (kp->p_stat) { 219 220 case SSTOP: 221 *cp = 'T'; 222 break; 223 224 case SSLEEP: 225 if (flag & P_SINTR) /* interruptible (long) */ 226 *cp = kp->p_slptime >= maxslp ? 'I' : 'S'; 227 else 228 *cp = 'D'; 229 break; 230 231 case SRUN: 232 case SIDL: 233 case SONPROC: 234 state = *cp = 'R'; 235 break; 236 237 case SZOMB: 238 *cp = 'Z'; 239 break; 240 241 default: 242 *cp = '?'; 243 } 244 cp++; 245 246 if (kp->p_nice < NZERO) 247 *cp++ = '<'; 248 else if (kp->p_nice > NZERO) 249 *cp++ = 'N'; 250 if (flag & P_TRACED) 251 *cp++ = 'X'; 252 if (flag & P_SYSTRACE) 253 *cp++ = 'x'; 254 if (flag & P_WEXIT && kp->p_stat != SZOMB) 255 *cp++ = 'E'; 256 if (flag & P_PPWAIT) 257 *cp++ = 'V'; 258 if (flag & P_SYSTEM) 259 *cp++ = 'K'; 260 if ((flag & P_SYSTEM) == 0 && 261 kp->p_rlim_rss_cur / 1024 < pgtok(kp->p_vm_rssize)) 262 *cp++ = '>'; 263 if (kp->p_eflag & EPROC_SLEADER) 264 *cp++ = 's'; 265 if ((flag & P_CONTROLT) && kp->p__pgid == kp->p_tpgid) 266 *cp++ = '+'; 267 *cp = '\0'; 268 269 if (state == 'R' && ncpu && kp->p_cpuid != KI_NOCPU) { 270 char pbuf[16]; 271 272 snprintf(pbuf, sizeof pbuf, "/%llu", kp->p_cpuid); 273 *++cp = '\0'; 274 strlcat(buf, pbuf, sizeof buf); 275 cp = buf + strlen(buf); 276 } 277 278 (void)printf("%-*s", v->width, buf); 279 } 280 281 void 282 pri(const struct kinfo_proc2 *kp, VARENT *ve) 283 { 284 VAR *v; 285 286 v = ve->var; 287 (void)printf("%*d", v->width, kp->p_priority - PZERO); 288 } 289 290 void 291 pnice(const struct kinfo_proc2 *kp, VARENT *ve) 292 { 293 VAR *v; 294 v = ve->var; 295 (void)printf("%*d", v->width, kp->p_nice - NZERO); 296 } 297 298 void 299 euname(const struct kinfo_proc2 *kp, VARENT *ve) 300 { 301 VAR *v; 302 303 v = ve->var; 304 (void)printf("%-*s", 305 (int)v->width, user_from_uid(kp->p_uid, 0)); 306 } 307 308 void 309 runame(const struct kinfo_proc2 *kp, VARENT *ve) 310 { 311 VAR *v; 312 313 v = ve->var; 314 (void)printf("%-*s", 315 (int)v->width, user_from_uid(kp->p_ruid, 0)); 316 } 317 318 void 319 gname(const struct kinfo_proc2 *kp, VARENT *ve) 320 { 321 VAR *v; 322 323 v = ve->var; 324 (void)printf("%-*s", 325 (int)v->width, group_from_gid(kp->p_gid, 0)); 326 } 327 328 void 329 rgname(const struct kinfo_proc2 *kp, VARENT *ve) 330 { 331 VAR *v; 332 333 v = ve->var; 334 (void)printf("%-*s", 335 (int)v->width, group_from_gid(kp->p_rgid, 0)); 336 } 337 338 void 339 tdev(const struct kinfo_proc2 *kp, VARENT *ve) 340 { 341 VAR *v; 342 dev_t dev; 343 char buff[16]; 344 345 v = ve->var; 346 dev = kp->p_tdev; 347 if (dev == NODEV) 348 (void)printf("%*s", v->width, "??"); 349 else { 350 (void)snprintf(buff, sizeof(buff), 351 "%d/%d", major(dev), minor(dev)); 352 (void)printf("%*s", v->width, buff); 353 } 354 } 355 356 void 357 tname(const struct kinfo_proc2 *kp, VARENT *ve) 358 { 359 VAR *v; 360 dev_t dev; 361 char *ttname; 362 363 v = ve->var; 364 dev = kp->p_tdev; 365 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 366 (void)printf("%-*s", v->width, "??"); 367 else { 368 if (strncmp(ttname, "tty", 3) == 0) 369 ttname += 3; 370 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, 371 kp->p_eflag & EPROC_CTTY ? ' ' : '-'); 372 } 373 } 374 375 void 376 longtname(const struct kinfo_proc2 *kp, VARENT *ve) 377 { 378 VAR *v; 379 dev_t dev; 380 char *ttname; 381 382 v = ve->var; 383 dev = kp->p_tdev; 384 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 385 (void)printf("%-*s", v->width, "??"); 386 else 387 (void)printf("%-*s", v->width, ttname); 388 } 389 390 void 391 started(const struct kinfo_proc2 *kp, VARENT *ve) 392 { 393 VAR *v; 394 static time_t now; 395 time_t startt; 396 struct tm *tp; 397 char buf[100]; 398 399 v = ve->var; 400 if (!kp->p_uvalid) { 401 (void)printf("%-*s", v->width, "-"); 402 return; 403 } 404 405 startt = kp->p_ustart_sec; 406 tp = localtime(&startt); 407 if (!now) 408 (void)time(&now); 409 if (now - kp->p_ustart_sec < 24 * SECSPERHOUR) { 410 (void)strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp); 411 } else if (now - kp->p_ustart_sec < 7 * SECSPERDAY) { 412 (void)strftime(buf, sizeof(buf) - 1, "%a%I%p", tp); 413 } else 414 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 415 (void)printf("%-*s", v->width, buf); 416 } 417 418 void 419 lstarted(const struct kinfo_proc2 *kp, VARENT *ve) 420 { 421 VAR *v; 422 time_t startt; 423 char buf[100]; 424 425 v = ve->var; 426 if (!kp->p_uvalid) { 427 (void)printf("%-*s", v->width, "-"); 428 return; 429 } 430 startt = kp->p_ustart_sec; 431 (void)strftime(buf, sizeof(buf) -1, "%c", 432 localtime(&startt)); 433 (void)printf("%-*s", v->width, buf); 434 } 435 436 void 437 wchan(const struct kinfo_proc2 *kp, VARENT *ve) 438 { 439 VAR *v; 440 441 v = ve->var; 442 if (kp->p_wchan) { 443 int n; 444 445 if (kp->p_wmesg) { 446 n = min(v->width, WMESGLEN); 447 (void)printf("%-*.*s", n, n, kp->p_wmesg); 448 if (v->width > n) 449 (void)printf("%*s", v->width - n, ""); 450 } else 451 (void)printf("%-*lx", v->width, 452 (long)kp->p_wchan &~ KERNBASE); 453 } else 454 (void)printf("%-*s", v->width, "-"); 455 } 456 457 void 458 vsize(const struct kinfo_proc2 *kp, VARENT *ve) 459 { 460 VAR *v; 461 462 v = ve->var; 463 (void)printf("%*d", v->width, 464 pgtok(kp->p_vm_dsize + kp->p_vm_ssize + kp->p_vm_tsize)); 465 } 466 467 void 468 rssize(const struct kinfo_proc2 *kp, VARENT *ve) 469 { 470 VAR *v; 471 472 v = ve->var; 473 /* XXX don't have info about shared */ 474 (void)printf("%*d", v->width, (kp->p_flag & P_SYSTEM) ? 0 : 475 pgtok(kp->p_vm_rssize)); 476 } 477 478 void 479 p_rssize(const struct kinfo_proc2 *kp, VARENT *ve) 480 { 481 VAR *v; 482 483 v = ve->var; 484 (void)printf("%*d", v->width, (kp->p_flag & P_SYSTEM) ? 0 : 485 pgtok(kp->p_vm_rssize)); 486 } 487 488 void 489 cputime(const struct kinfo_proc2 *kp, VARENT *ve) 490 { 491 VAR *v; 492 long secs; 493 long psecs; /* "parts" of a second. first micro, then centi */ 494 char obuff[128]; 495 496 v = ve->var; 497 if (kp->p_stat == SZOMB || !kp->p_uvalid) { 498 secs = 0; 499 psecs = 0; 500 } else { 501 /* 502 * This counts time spent handling interrupts. We could 503 * fix this, but it is not 100% trivial (and interrupt 504 * time fractions only work on the sparc anyway). XXX 505 */ 506 secs = kp->p_rtime_sec; 507 psecs = kp->p_rtime_usec; 508 if (sumrusage) { 509 secs += kp->p_uctime_sec; 510 psecs += kp->p_uctime_usec; 511 } 512 /* 513 * round and scale to 100's 514 */ 515 psecs = (psecs + 5000) / 10000; 516 secs += psecs / 100; 517 psecs = psecs % 100; 518 } 519 (void)snprintf(obuff, sizeof(obuff), 520 "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); 521 (void)printf("%*s", v->width, obuff); 522 } 523 524 double 525 getpcpu(const struct kinfo_proc2 *kp) 526 { 527 double d; 528 529 if (fscale == 0) 530 return (0.0); 531 532 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 533 534 /* XXX - I don't like this */ 535 if (kp->p_swtime == 0) 536 return (0.0); 537 if (rawcpu) 538 return (100.0 * fxtofl(kp->p_pctcpu)); 539 540 d = kp->p_swtime * log(fxtofl(ccpu)); 541 if (d < -700.0) 542 d = 0.0; /* avoid IEEE underflow */ 543 else 544 d = exp(d); 545 if (d == 1.0) 546 return (0.0); 547 return (100.0 * fxtofl(kp->p_pctcpu) / 548 (1.0 - d)); 549 } 550 551 void 552 pcpu(const struct kinfo_proc2 *kp, VARENT *ve) 553 { 554 VAR *v; 555 556 v = ve->var; 557 (void)printf("%*.1f", v->width, getpcpu(kp)); 558 } 559 560 double 561 getpmem(const struct kinfo_proc2 *kp) 562 { 563 double fracmem; 564 int szptudot; 565 566 if (mempages == 0) 567 return (0.0); 568 569 if (kp->p_flag & P_SYSTEM) 570 return (0.0); 571 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 572 szptudot = USPACE/getpagesize(); 573 /* XXX don't have info about shared */ 574 fracmem = ((float)kp->p_vm_rssize + szptudot)/mempages; 575 return (100.0 * fracmem); 576 } 577 578 void 579 pmem(const struct kinfo_proc2 *kp, VARENT *ve) 580 { 581 VAR *v; 582 583 v = ve->var; 584 (void)printf("%*.1f", v->width, getpmem(kp)); 585 } 586 587 void 588 pagein(const struct kinfo_proc2 *kp, VARENT *ve) 589 { 590 VAR *v; 591 592 v = ve->var; 593 (void)printf("%*llu", v->width, 594 kp->p_uvalid ? kp->p_uru_majflt : 0); 595 } 596 597 void 598 maxrss(const struct kinfo_proc2 *kp, VARENT *ve) 599 { 600 VAR *v; 601 602 v = ve->var; 603 (void)printf("%*lld", v->width, kp->p_rlim_rss_cur / 1024); 604 } 605 606 void 607 tsize(const struct kinfo_proc2 *kp, VARENT *ve) 608 { 609 VAR *v; 610 611 v = ve->var; 612 (void)printf("%*d", v->width, pgtok(kp->p_vm_tsize)); 613 } 614 615 void 616 dsize(const struct kinfo_proc2 *kp, VARENT *ve) 617 { 618 VAR *v; 619 620 v = ve->var; 621 (void)printf("%*d", v->width, pgtok(kp->p_vm_dsize)); 622 } 623 624 void 625 ssize(const struct kinfo_proc2 *kp, VARENT *ve) 626 { 627 VAR *v; 628 629 v = ve->var; 630 (void)printf("%*d", v->width, pgtok(kp->p_vm_ssize)); 631 } 632 633 /* 634 * Generic output routines. Print fields from various prototype 635 * structures. 636 */ 637 static void 638 printval(char *bp, VAR *v) 639 { 640 char ofmt[32]; 641 642 snprintf(ofmt, sizeof(ofmt), "%%%s*%s", (v->flag & LJUST) ? "-" : "", 643 v->fmt); 644 645 /* 646 * Note that the "INF127" check is nonsensical for types 647 * that are or can be signed. 648 */ 649 #define GET(type) (*(type *)bp) 650 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 651 652 switch (v->type) { 653 case INT8: 654 (void)printf(ofmt, v->width, GET(int8_t)); 655 break; 656 case UINT8: 657 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int8_t))); 658 break; 659 case INT16: 660 (void)printf(ofmt, v->width, GET(int16_t)); 661 break; 662 case UINT16: 663 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int16_t))); 664 break; 665 case INT32: 666 (void)printf(ofmt, v->width, GET(int32_t)); 667 break; 668 case UINT32: 669 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int32_t))); 670 break; 671 case INT64: 672 (void)printf(ofmt, v->width, GET(int64_t)); 673 break; 674 case UINT64: 675 (void)printf(ofmt, v->width, CHK_INF127(GET(u_int64_t))); 676 break; 677 default: 678 errx(1, "unknown type %d", v->type); 679 } 680 #undef GET 681 #undef CHK_INF127 682 } 683 684 void 685 pvar(const struct kinfo_proc2 *kp, VARENT *ve) 686 { 687 VAR *v; 688 689 v = ve->var; 690 if ((v->flag & USER) && !kp->p_uvalid) 691 (void)printf("%*s", v->width, "-"); 692 else 693 printval((char *)kp + v->off, v); 694 } 695 696 void 697 emulname(const struct kinfo_proc2 *kp, VARENT *ve) 698 { 699 VAR *v; 700 701 v = ve->var; 702 703 (void)printf("%-*s", (int)v->width, kp->p_emul); 704 } 705