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