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