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