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