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