1 /* $NetBSD: print.c,v 1.130 2018/09/19 15:20:39 maxv Exp $ */ 2 3 /* 4 * Copyright (c) 2000, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Simon Burge. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1990, 1993, 1994 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61 #include <sys/cdefs.h> 62 #ifndef lint 63 #if 0 64 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; 65 #else 66 __RCSID("$NetBSD: print.c,v 1.130 2018/09/19 15:20:39 maxv Exp $"); 67 #endif 68 #endif /* not lint */ 69 70 #include <sys/param.h> 71 #include <sys/time.h> 72 #include <sys/resource.h> 73 #include <sys/lwp.h> 74 #include <sys/proc.h> 75 #include <sys/stat.h> 76 #include <sys/ucred.h> 77 #include <sys/sysctl.h> 78 79 #include <err.h> 80 #include <grp.h> 81 #include <kvm.h> 82 #include <math.h> 83 #include <nlist.h> 84 #include <pwd.h> 85 #include <stddef.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <time.h> 90 #include <tzfile.h> 91 #include <unistd.h> 92 93 #include "ps.h" 94 95 static char *cmdpart(char *); 96 static void printval(void *, VAR *, enum mode); 97 static int titlecmp(char *, char **); 98 99 static void doubleprintorsetwidth(VAR *, double, int, enum mode); 100 static void intprintorsetwidth(VAR *, int, enum mode); 101 static void strprintorsetwidth(VAR *, const char *, enum mode); 102 103 static time_t now; 104 105 #define min(a,b) ((a) <= (b) ? (a) : (b)) 106 107 static int 108 iwidth(u_int64_t v) 109 { 110 u_int64_t nlim, lim; 111 int w = 1; 112 113 for (lim = 10; v >= lim; lim = nlim) { 114 nlim = lim * 10; 115 w++; 116 if (nlim < lim) 117 break; 118 } 119 return w; 120 } 121 122 static char * 123 cmdpart(char *arg0) 124 { 125 char *cp; 126 127 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 128 } 129 130 void 131 printheader(void) 132 { 133 int len; 134 VAR *v; 135 struct varent *vent; 136 static int firsttime = 1; 137 static int noheader = 0; 138 139 /* 140 * If all the columns have user-specified null headers, 141 * don't print the blank header line at all. 142 */ 143 if (firsttime) { 144 SIMPLEQ_FOREACH(vent, &displaylist, next) { 145 if (vent->var->header[0]) 146 break; 147 } 148 if (vent == NULL) { 149 noheader = 1; 150 firsttime = 0; 151 } 152 153 } 154 if (noheader) 155 return; 156 157 SIMPLEQ_FOREACH(vent, &displaylist, next) { 158 v = vent->var; 159 if (firsttime) { 160 len = strlen(v->header); 161 if (len > v->width) 162 v->width = len; 163 totwidth += v->width + 1; /* +1 for space */ 164 } 165 if (v->flag & LJUST) { 166 if (SIMPLEQ_NEXT(vent, next) == NULL) /* last one */ 167 (void)printf("%s", v->header); 168 else 169 (void)printf("%-*s", v->width, 170 v->header); 171 } else 172 (void)printf("%*s", v->width, v->header); 173 if (SIMPLEQ_NEXT(vent, next) != NULL) 174 (void)putchar(' '); 175 } 176 (void)putchar('\n'); 177 if (firsttime) { 178 firsttime = 0; 179 totwidth--; /* take off last space */ 180 } 181 } 182 183 /* 184 * Return 1 if the command name in the argument vector (u-area) does 185 * not match the command name (p_comm) 186 */ 187 static int 188 titlecmp(char *name, char **argv) 189 { 190 char *title; 191 int namelen; 192 193 194 /* no argument vector == no match; system processes/threads do that */ 195 if (argv == 0 || argv[0] == 0) 196 return (1); 197 198 title = cmdpart(argv[0]); 199 200 /* the basename matches */ 201 if (!strcmp(name, title)) 202 return (0); 203 204 /* handle login shells, by skipping the leading - */ 205 if (title[0] == '-' && !strcmp(name, title + 1)) 206 return (0); 207 208 namelen = strlen(name); 209 210 /* handle daemons that report activity as daemonname: activity */ 211 if (argv[1] == 0 && 212 !strncmp(name, title, namelen) && 213 title[namelen + 0] == ':' && 214 title[namelen + 1] == ' ') 215 return (0); 216 217 return (1); 218 } 219 220 static void 221 doubleprintorsetwidth(VAR *v, double val, int prec, enum mode mode) 222 { 223 int fmtlen; 224 225 if (mode == WIDTHMODE) { 226 if (val < 0.0 && val < v->longestnd) { 227 fmtlen = (int)log10(-val) + prec + 2; 228 v->longestnd = val; 229 if (fmtlen > v->width) 230 v->width = fmtlen; 231 } else if (val > 0.0 && val > v->longestpd) { 232 fmtlen = (int)log10(val) + prec + 1; 233 v->longestpd = val; 234 if (fmtlen > v->width) 235 v->width = fmtlen; 236 } 237 } else { 238 (void)printf("%*.*f", v->width, prec, val); 239 } 240 } 241 242 static void 243 intprintorsetwidth(VAR *v, int val, enum mode mode) 244 { 245 int fmtlen; 246 247 if (mode == WIDTHMODE) { 248 if (val < 0 && val < v->longestn) { 249 v->longestn = val; 250 fmtlen = iwidth(-val) + 1; 251 if (fmtlen > v->width) 252 v->width = fmtlen; 253 } else if (val > 0 && val > v->longestp) { 254 v->longestp = val; 255 fmtlen = iwidth(val); 256 if (fmtlen > v->width) 257 v->width = fmtlen; 258 } 259 } else 260 (void)printf("%*d", v->width, val); 261 } 262 263 static void 264 strprintorsetwidth(VAR *v, const char *str, enum mode mode) 265 { 266 int len; 267 268 if (mode == WIDTHMODE) { 269 len = strlen(str); 270 if (len > v->width) 271 v->width = len; 272 } else { 273 if (v->flag & LJUST) 274 (void)printf("%-*.*s", v->width, v->width, str); 275 else 276 (void)printf("%*.*s", v->width, v->width, str); 277 } 278 } 279 280 void 281 command(struct pinfo *pi, VARENT *ve, enum mode mode) 282 { 283 struct kinfo_proc2 *ki = pi->ki; 284 VAR *v; 285 int left; 286 char **argv, **p, *name; 287 288 if (mode == WIDTHMODE) 289 return; 290 291 v = ve->var; 292 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 293 if (SIMPLEQ_NEXT(ve, next) == NULL) { 294 left = termwidth - (totwidth - v->width); 295 if (left < 1) /* already wrapped, just use std width */ 296 left = v->width; 297 } else 298 left = v->width; 299 } else 300 left = -1; 301 if (needenv && kd) { 302 argv = kvm_getenvv2(kd, ki, termwidth); 303 if ((p = argv) != NULL) { 304 while (*p) { 305 fmt_puts(*p, &left); 306 p++; 307 fmt_putc(' ', &left); 308 } 309 } 310 } 311 if (needcomm) { 312 if (pi->prefix) 313 (void)fmt_puts(pi->prefix, &left); 314 name = ki->p_comm; 315 if (!commandonly) { 316 argv = kvm_getargv2(kd, ki, termwidth); 317 if ((p = argv) != NULL) { 318 while (*p) { 319 fmt_puts(*p, &left); 320 p++; 321 fmt_putc(' ', &left); 322 if (v->flag & ARGV0) 323 break; 324 } 325 if (!(v->flag & ARGV0) && 326 titlecmp(name, argv)) { 327 /* 328 * append the real command name within 329 * parentheses, if the command name 330 * does not match the one in the 331 * argument vector 332 */ 333 fmt_putc('(', &left); 334 fmt_puts(name, &left); 335 fmt_putc(')', &left); 336 } 337 } else { 338 /* 339 * Commands that don't set an argv vector 340 * are printed with square brackets if they 341 * are system commands. Otherwise they are 342 * printed within parentheses. 343 */ 344 if (ki->p_flag & P_SYSTEM) { 345 fmt_putc('[', &left); 346 fmt_puts(name, &left); 347 fmt_putc(']', &left); 348 } else { 349 fmt_putc('(', &left); 350 fmt_puts(name, &left); 351 fmt_putc(')', &left); 352 } 353 } 354 } else { 355 fmt_puts(name, &left); 356 } 357 } 358 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 359 (void)printf("%*s", left, ""); 360 } 361 362 void 363 groups(struct pinfo *pi, VARENT *ve, enum mode mode) 364 { 365 struct kinfo_proc2 *ki = pi->ki; 366 VAR *v; 367 int left, i; 368 char buf[16], *p; 369 370 if (mode == WIDTHMODE) 371 return; 372 373 v = ve->var; 374 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 375 if (SIMPLEQ_NEXT(ve, next) == NULL) { 376 left = termwidth - (totwidth - v->width); 377 if (left < 1) /* already wrapped, just use std width */ 378 left = v->width; 379 } else 380 left = v->width; 381 } else 382 left = -1; 383 384 if (ki->p_ngroups == 0) 385 fmt_putc('-', &left); 386 387 for (i = 0; i < ki->p_ngroups; i++) { 388 (void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]); 389 if (i) 390 fmt_putc(' ', &left); 391 for (p = &buf[0]; *p; p++) 392 fmt_putc(*p, &left); 393 } 394 395 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 396 (void)printf("%*s", left, ""); 397 } 398 399 void 400 groupnames(struct pinfo *pi, VARENT *ve, enum mode mode) 401 { 402 struct kinfo_proc2 *ki = pi->ki; 403 VAR *v; 404 int left, i; 405 const char *p; 406 407 if (mode == WIDTHMODE) 408 return; 409 410 v = ve->var; 411 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 412 if (SIMPLEQ_NEXT(ve, next) == NULL) { 413 left = termwidth - (totwidth - v->width); 414 if (left < 1) /* already wrapped, just use std width */ 415 left = v->width; 416 } else 417 left = v->width; 418 } else 419 left = -1; 420 421 if (ki->p_ngroups == 0) 422 fmt_putc('-', &left); 423 424 for (i = 0; i < ki->p_ngroups; i++) { 425 if (i) 426 fmt_putc(' ', &left); 427 for (p = group_from_gid(ki->p_groups[i], 0); *p; p++) 428 fmt_putc(*p, &left); 429 } 430 431 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 432 (void)printf("%*s", left, ""); 433 } 434 435 void 436 ucomm(struct pinfo *pi, VARENT *ve, enum mode mode) 437 { 438 struct kinfo_proc2 *k = pi->ki; 439 char buf[MAXPATHLEN], *p; 440 VAR *v; 441 442 v = ve->var; 443 if (pi->prefix) 444 snprintf(p = buf, sizeof(buf), "%s%s", pi->prefix, k->p_comm); 445 else 446 p = k->p_comm; 447 strprintorsetwidth(v, p, mode); 448 } 449 450 void 451 emul(struct pinfo *pi, VARENT *ve, enum mode mode) 452 { 453 struct kinfo_proc2 *k = pi->ki; 454 VAR *v; 455 456 v = ve->var; 457 strprintorsetwidth(v, k->p_ename, mode); 458 } 459 460 void 461 logname(struct pinfo *pi, VARENT *ve, enum mode mode) 462 { 463 struct kinfo_proc2 *k = pi->ki; 464 VAR *v; 465 466 v = ve->var; 467 strprintorsetwidth(v, k->p_login, mode); 468 } 469 470 void 471 state(struct pinfo *pi, VARENT *ve, enum mode mode) 472 { 473 struct kinfo_proc2 *k = pi->ki; 474 int flag, is_zombie; 475 char *cp; 476 VAR *v; 477 char buf[16]; 478 479 is_zombie = 0; 480 v = ve->var; 481 flag = k->p_flag; 482 cp = buf; 483 484 /* 485 * NOTE: There are historical letters, which are no longer used: 486 * 487 * - W: indicated that process is swapped out. 488 * - L: indicated non-zero l_holdcnt (i.e. that process was 489 * prevented from swapping-out. 490 * 491 * These letters should not be used for new states to avoid 492 * conflicts with old applications which might depend on them. 493 */ 494 switch (k->p_stat) { 495 496 case LSSTOP: 497 *cp = 'T'; 498 break; 499 500 case LSSLEEP: 501 if (flag & L_SINTR) /* interruptable (long) */ 502 *cp = (int)k->p_slptime >= maxslp ? 'I' : 'S'; 503 else 504 *cp = 'D'; 505 break; 506 507 case LSRUN: 508 case LSIDL: 509 *cp = 'R'; 510 break; 511 512 case LSONPROC: 513 *cp = 'O'; 514 break; 515 516 case LSZOMB: 517 *cp = 'Z'; 518 is_zombie = 1; 519 break; 520 521 case LSSUSPENDED: 522 *cp = 'U'; 523 break; 524 525 default: 526 *cp = '?'; 527 } 528 cp++; 529 if (k->p_nice < NZERO) 530 *cp++ = '<'; 531 else if (k->p_nice > NZERO) 532 *cp++ = 'N'; 533 if (flag & P_TRACED) 534 *cp++ = 'X'; 535 if (flag & P_WEXIT && !is_zombie) 536 *cp++ = 'E'; 537 if (flag & P_PPWAIT) 538 *cp++ = 'V'; 539 if (flag & P_SYSTEM) 540 *cp++ = 'K'; 541 if (k->p_eflag & EPROC_SLEADER) 542 *cp++ = 's'; 543 if (flag & P_SA) 544 *cp++ = 'a'; 545 else if (k->p_nlwps > 1) 546 *cp++ = 'l'; 547 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid) 548 *cp++ = '+'; 549 *cp = '\0'; 550 strprintorsetwidth(v, buf, mode); 551 } 552 553 void 554 lstate(struct pinfo *pi, VARENT *ve, enum mode mode) 555 { 556 struct kinfo_lwp *k = pi->li; 557 int flag; 558 char *cp; 559 VAR *v; 560 char buf[16]; 561 562 v = ve->var; 563 flag = k->l_flag; 564 cp = buf; 565 566 switch (k->l_stat) { 567 568 case LSSTOP: 569 *cp = 'T'; 570 break; 571 572 case LSSLEEP: 573 if (flag & L_SINTR) /* interruptible (long) */ 574 *cp = (int)k->l_slptime >= maxslp ? 'I' : 'S'; 575 else 576 *cp = 'D'; 577 break; 578 579 case LSRUN: 580 case LSIDL: 581 *cp = 'R'; 582 break; 583 584 case LSONPROC: 585 *cp = 'O'; 586 break; 587 588 case LSZOMB: 589 case LSDEAD: 590 *cp = 'Z'; 591 break; 592 593 case LSSUSPENDED: 594 *cp = 'U'; 595 break; 596 597 default: 598 *cp = '?'; 599 } 600 cp++; 601 if (flag & L_SYSTEM) 602 *cp++ = 'K'; 603 if (flag & L_SA) 604 *cp++ = 'a'; 605 if (flag & L_DETACHED) 606 *cp++ = '-'; 607 *cp = '\0'; 608 strprintorsetwidth(v, buf, mode); 609 } 610 611 void 612 pnice(struct pinfo *pi, VARENT *ve, enum mode mode) 613 { 614 struct kinfo_proc2 *k = pi->ki; 615 VAR *v; 616 617 v = ve->var; 618 intprintorsetwidth(v, k->p_nice - NZERO, mode); 619 } 620 621 void 622 pri(struct pinfo *pi, VARENT *ve, enum mode mode) 623 { 624 struct kinfo_lwp *l = pi->li; 625 VAR *v; 626 627 v = ve->var; 628 intprintorsetwidth(v, l->l_priority, mode); 629 } 630 631 void 632 usrname(struct pinfo *pi, VARENT *ve, enum mode mode) 633 { 634 struct kinfo_proc2 *k = pi->ki; 635 VAR *v; 636 637 v = ve->var; 638 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode); 639 } 640 641 void 642 runame(struct pinfo *pi, VARENT *ve, enum mode mode) 643 { 644 struct kinfo_proc2 *k = pi->ki; 645 VAR *v; 646 647 v = ve->var; 648 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode); 649 } 650 651 void 652 svuname(struct pinfo *pi, VARENT *ve, enum mode mode) 653 { 654 struct kinfo_proc2 *k = pi->ki; 655 VAR *v; 656 657 v = ve->var; 658 strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode); 659 } 660 661 void 662 gname(struct pinfo *pi, VARENT *ve, enum mode mode) 663 { 664 struct kinfo_proc2 *k = pi->ki; 665 VAR *v; 666 667 v = ve->var; 668 strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode); 669 } 670 671 void 672 rgname(struct pinfo *pi, VARENT *ve, enum mode mode) 673 { 674 struct kinfo_proc2 *k = pi->ki; 675 VAR *v; 676 677 v = ve->var; 678 strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode); 679 } 680 681 void 682 svgname(struct pinfo *pi, VARENT *ve, enum mode mode) 683 { 684 struct kinfo_proc2 *k = pi->ki; 685 VAR *v; 686 687 v = ve->var; 688 strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode); 689 } 690 691 void 692 tdev(struct pinfo *pi, VARENT *ve, enum mode mode) 693 { 694 struct kinfo_proc2 *k = pi->ki; 695 VAR *v; 696 dev_t dev; 697 char buff[16]; 698 699 v = ve->var; 700 dev = k->p_tdev; 701 if (dev == NODEV) { 702 if (mode == PRINTMODE) 703 (void)printf("%*s", v->width, "?"); 704 else 705 if (v->width < 2) 706 v->width = 2; 707 } else { 708 (void)snprintf(buff, sizeof(buff), 709 "%lld/%lld", (long long)major(dev), (long long)minor(dev)); 710 strprintorsetwidth(v, buff, mode); 711 } 712 } 713 714 void 715 tname(struct pinfo *pi, VARENT *ve, enum mode mode) 716 { 717 struct kinfo_proc2 *k = pi->ki; 718 VAR *v; 719 dev_t dev; 720 const char *ttname; 721 int noctty; 722 723 v = ve->var; 724 dev = k->p_tdev; 725 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 726 if (mode == PRINTMODE) 727 (void)printf("%-*s", v->width, "?"); 728 else 729 if (v->width < 2) 730 v->width = 2; 731 } else { 732 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0; 733 if (mode == WIDTHMODE) { 734 int fmtlen; 735 736 fmtlen = strlen(ttname) + noctty; 737 if (v->width < fmtlen) 738 v->width = fmtlen; 739 } else { 740 if (noctty) 741 (void)printf("%-*s-", v->width - 1, ttname); 742 else 743 (void)printf("%-*s", v->width, ttname); 744 } 745 } 746 } 747 748 void 749 longtname(struct pinfo *pi, VARENT *ve, enum mode mode) 750 { 751 struct kinfo_proc2 *k = pi->ki; 752 VAR *v; 753 dev_t dev; 754 const char *ttname; 755 756 v = ve->var; 757 dev = k->p_tdev; 758 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 759 if (mode == PRINTMODE) 760 (void)printf("%-*s", v->width, "?"); 761 else 762 if (v->width < 2) 763 v->width = 2; 764 } else { 765 strprintorsetwidth(v, ttname, mode); 766 } 767 } 768 769 void 770 started(struct pinfo *pi, VARENT *ve, enum mode mode) 771 { 772 struct kinfo_proc2 *k = pi->ki; 773 VAR *v; 774 time_t startt; 775 struct tm *tp; 776 char buf[100], *cp; 777 778 v = ve->var; 779 if (!k->p_uvalid) { 780 if (mode == PRINTMODE) 781 (void)printf("%*s", v->width, "-"); 782 return; 783 } 784 785 startt = k->p_ustart_sec; 786 tp = localtime(&startt); 787 if (now == 0) 788 (void)time(&now); 789 if (now - k->p_ustart_sec < SECSPERDAY) 790 /* I *hate* SCCS... */ 791 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 792 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 793 /* I *hate* SCCS... */ 794 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 795 else 796 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 797 /* %e and %l can start with a space. */ 798 cp = buf; 799 if (*cp == ' ') 800 cp++; 801 strprintorsetwidth(v, cp, mode); 802 } 803 804 void 805 lstarted(struct pinfo *pi, VARENT *ve, enum mode mode) 806 { 807 struct kinfo_proc2 *k = pi->ki; 808 VAR *v; 809 time_t startt; 810 char buf[100]; 811 812 v = ve->var; 813 if (!k->p_uvalid) { 814 /* 815 * Minimum width is less than header - we don't 816 * need to check it every time. 817 */ 818 if (mode == PRINTMODE) 819 (void)printf("%*s", v->width, "-"); 820 return; 821 } 822 startt = k->p_ustart_sec; 823 824 /* assume all times are the same length */ 825 if (mode != WIDTHMODE || v->width == 0) { 826 (void)strftime(buf, sizeof(buf) -1, "%c", 827 localtime(&startt)); 828 strprintorsetwidth(v, buf, mode); 829 } 830 } 831 832 void 833 elapsed(struct pinfo *pi, VARENT *ve, enum mode mode) 834 { 835 struct kinfo_proc2 *k = pi->ki; 836 VAR *v; 837 int32_t origseconds, secs, mins, hours, days; 838 int fmtlen, printed_something; 839 840 v = ve->var; 841 if (k->p_uvalid == 0) { 842 origseconds = 0; 843 } else { 844 if (now == 0) 845 (void)time(&now); 846 origseconds = now - k->p_ustart_sec; 847 if (origseconds < 0) { 848 /* 849 * Don't try to be fancy if the machine's 850 * clock has been rewound to before the 851 * process "started". 852 */ 853 origseconds = 0; 854 } 855 } 856 857 secs = origseconds; 858 mins = secs / SECSPERMIN; 859 secs %= SECSPERMIN; 860 hours = mins / MINSPERHOUR; 861 mins %= MINSPERHOUR; 862 days = hours / HOURSPERDAY; 863 hours %= HOURSPERDAY; 864 865 if (mode == WIDTHMODE) { 866 if (origseconds == 0) 867 /* non-zero so fmtlen is calculated at least once */ 868 origseconds = 1; 869 870 if (origseconds > v->longestp) { 871 v->longestp = origseconds; 872 873 if (days > 0) { 874 /* +9 for "-hh:mm:ss" */ 875 fmtlen = iwidth(days) + 9; 876 } else if (hours > 0) { 877 /* +6 for "mm:ss" */ 878 fmtlen = iwidth(hours) + 6; 879 } else { 880 /* +3 for ":ss" */ 881 fmtlen = iwidth(mins) + 3; 882 } 883 884 if (fmtlen > v->width) 885 v->width = fmtlen; 886 } 887 } else { 888 printed_something = 0; 889 fmtlen = v->width; 890 891 if (days > 0) { 892 (void)printf("%*d", fmtlen - 9, days); 893 printed_something = 1; 894 } else if (fmtlen > 9) { 895 (void)printf("%*s", fmtlen - 9, ""); 896 } 897 if (fmtlen > 9) 898 fmtlen = 9; 899 900 if (printed_something) { 901 (void)printf("-%.*d", fmtlen - 7, hours); 902 printed_something = 1; 903 } else if (hours > 0) { 904 (void)printf("%*d", fmtlen - 6, hours); 905 printed_something = 1; 906 } else if (fmtlen > 6) { 907 (void)printf("%*s", fmtlen - 6, ""); 908 } 909 if (fmtlen > 6) 910 fmtlen = 6; 911 912 /* Don't need to set fmtlen or printed_something any more... */ 913 if (printed_something) { 914 (void)printf(":%.*d", fmtlen - 4, mins); 915 } else if (mins > 0) { 916 (void)printf("%*d", fmtlen - 3, mins); 917 } else if (fmtlen > 3) { 918 (void)printf("%*s", fmtlen - 3, "0"); 919 } 920 921 (void)printf(":%.2d", secs); 922 } 923 } 924 925 void 926 wchan(struct pinfo *pi, VARENT *ve, enum mode mode) 927 { 928 struct kinfo_lwp *l = pi->li; 929 VAR *v; 930 931 v = ve->var; 932 if (l->l_wmesg[0]) { 933 strprintorsetwidth(v, l->l_wmesg, mode); 934 v->width = min(v->width, KI_WMESGLEN); 935 } else { 936 if (mode == PRINTMODE) 937 (void)printf("%-*s", v->width, "-"); 938 } 939 } 940 941 #define pgtok(a) (((a)*(size_t)getpagesize())/1024) 942 943 void 944 vsize(struct pinfo *pi, VARENT *ve, enum mode mode) 945 { 946 struct kinfo_proc2 *k = pi->ki; 947 VAR *v; 948 949 v = ve->var; 950 intprintorsetwidth(v, pgtok(k->p_vm_msize), mode); 951 } 952 953 void 954 rssize(struct pinfo *pi, VARENT *ve, enum mode mode) 955 { 956 struct kinfo_proc2 *k = pi->ki; 957 VAR *v; 958 959 v = ve->var; 960 /* XXX don't have info about shared */ 961 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 962 } 963 964 void 965 p_rssize(struct pinfo *pi, VARENT *ve, enum mode mode) /* doesn't account for text */ 966 { 967 struct kinfo_proc2 *k = pi->ki; 968 VAR *v; 969 970 v = ve->var; 971 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 972 } 973 974 void 975 cpuid(struct pinfo *pi, VARENT *ve, enum mode mode) 976 { 977 struct kinfo_lwp *l = pi->li; 978 VAR *v; 979 980 v = ve->var; 981 intprintorsetwidth(v, l->l_cpuid, mode); 982 } 983 984 static void 985 cputime1(int32_t secs, int32_t psecs, VAR *v, enum mode mode) 986 { 987 int fmtlen; 988 989 /* 990 * round and scale to 100's 991 */ 992 psecs = (psecs + 5000) / 10000; 993 secs += psecs / 100; 994 psecs = psecs % 100; 995 996 if (mode == WIDTHMODE) { 997 /* 998 * Ugg, this is the only field where a value of 0 is longer 999 * than the column title. 1000 * Use SECSPERMIN, because secs is divided by that when 1001 * passed to iwidth(). 1002 */ 1003 if (secs == 0) 1004 secs = SECSPERMIN; 1005 1006 if (secs > v->longestp) { 1007 v->longestp = secs; 1008 /* "+6" for the ":%02ld.%02ld" in the printf() below */ 1009 fmtlen = iwidth(secs / SECSPERMIN) + 6; 1010 if (fmtlen > v->width) 1011 v->width = fmtlen; 1012 } 1013 } else { 1014 (void)printf("%*ld:%02ld.%02ld", v->width - 6, 1015 (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN), 1016 (long)psecs); 1017 } 1018 } 1019 1020 void 1021 cputime(struct pinfo *pi, VARENT *ve, enum mode mode) 1022 { 1023 struct kinfo_proc2 *k = pi->ki; 1024 VAR *v; 1025 int32_t secs; 1026 int32_t psecs; /* "parts" of a second. first micro, then centi */ 1027 1028 v = ve->var; 1029 1030 /* 1031 * This counts time spent handling interrupts. We could 1032 * fix this, but it is not 100% trivial (and interrupt 1033 * time fractions only work on the sparc anyway). XXX 1034 */ 1035 secs = k->p_rtime_sec; 1036 psecs = k->p_rtime_usec; 1037 if (sumrusage) { 1038 secs += k->p_uctime_sec; 1039 psecs += k->p_uctime_usec; 1040 } 1041 1042 cputime1(secs, psecs, v, mode); 1043 } 1044 1045 void 1046 lcputime(struct pinfo *pi, VARENT *ve, enum mode mode) 1047 { 1048 struct kinfo_lwp *l = pi->li; 1049 VAR *v; 1050 int32_t secs; 1051 int32_t psecs; /* "parts" of a second. first micro, then centi */ 1052 1053 v = ve->var; 1054 1055 secs = l->l_rtime_sec; 1056 psecs = l->l_rtime_usec; 1057 1058 cputime1(secs, psecs, v, mode); 1059 } 1060 1061 void 1062 pcpu(struct pinfo *pi, VARENT *ve, enum mode mode) 1063 { 1064 VAR *v; 1065 double dbl; 1066 1067 v = ve->var; 1068 dbl = pi->pcpu; 1069 doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode); 1070 } 1071 1072 double 1073 getpmem(const struct kinfo_proc2 *k) 1074 { 1075 double fracmem; 1076 int szptudot; 1077 1078 if (!nlistread) 1079 donlist(); 1080 1081 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 1082 szptudot = uspace/getpagesize(); 1083 /* XXX don't have info about shared */ 1084 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 1085 return (100.0 * fracmem); 1086 } 1087 1088 void 1089 pmem(struct pinfo *pi, VARENT *ve, enum mode mode) 1090 { 1091 struct kinfo_proc2 *k = pi->ki; 1092 VAR *v; 1093 1094 v = ve->var; 1095 doubleprintorsetwidth(v, getpmem(k), 1, mode); 1096 } 1097 1098 void 1099 pagein(struct pinfo *pi, VARENT *ve, enum mode mode) 1100 { 1101 struct kinfo_proc2 *k = pi->ki; 1102 VAR *v; 1103 1104 v = ve->var; 1105 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 1106 } 1107 1108 void 1109 maxrss(struct pinfo *pi, VARENT *ve, enum mode mode) 1110 { 1111 VAR *v; 1112 1113 v = ve->var; 1114 /* No need to check width! */ 1115 if (mode == PRINTMODE) 1116 (void)printf("%*s", v->width, "-"); 1117 } 1118 1119 void 1120 tsize(struct pinfo *pi, VARENT *ve, enum mode mode) 1121 { 1122 struct kinfo_proc2 *k = pi->ki; 1123 VAR *v; 1124 1125 v = ve->var; 1126 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 1127 } 1128 1129 /* 1130 * Generic output routines. Print fields from various prototype 1131 * structures. 1132 */ 1133 static void 1134 printval(void *bp, VAR *v, enum mode mode) 1135 { 1136 static char ofmt[32] = "%"; 1137 int width, vok, fmtlen; 1138 const char *fcp; 1139 char *cp; 1140 int64_t val; 1141 u_int64_t uval; 1142 1143 val = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1144 uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1145 1146 /* 1147 * Note that the "INF127" check is nonsensical for types 1148 * that are or can be signed. 1149 */ 1150 #define GET(type) (*(type *)bp) 1151 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 1152 1153 #define VSIGN 1 1154 #define VUNSIGN 2 1155 #define VPTR 3 1156 1157 if (mode == WIDTHMODE) { 1158 vok = 0; 1159 switch (v->type) { 1160 case CHAR: 1161 val = GET(char); 1162 vok = VSIGN; 1163 break; 1164 case UCHAR: 1165 uval = CHK_INF127(GET(u_char)); 1166 vok = VUNSIGN; 1167 break; 1168 case SHORT: 1169 val = GET(short); 1170 vok = VSIGN; 1171 break; 1172 case USHORT: 1173 uval = CHK_INF127(GET(u_short)); 1174 vok = VUNSIGN; 1175 break; 1176 case INT32: 1177 val = GET(int32_t); 1178 vok = VSIGN; 1179 break; 1180 case INT: 1181 val = GET(int); 1182 vok = VSIGN; 1183 break; 1184 case UINT: 1185 case UINT32: 1186 uval = CHK_INF127(GET(u_int)); 1187 vok = VUNSIGN; 1188 break; 1189 case LONG: 1190 val = GET(long); 1191 vok = VSIGN; 1192 break; 1193 case ULONG: 1194 uval = CHK_INF127(GET(u_long)); 1195 vok = VUNSIGN; 1196 break; 1197 case KPTR: 1198 uval = GET(u_int64_t); 1199 vok = VPTR; 1200 break; 1201 case KPTR24: 1202 uval = GET(u_int64_t); 1203 uval &= 0xffffff; 1204 vok = VPTR; 1205 break; 1206 case INT64: 1207 val = GET(int64_t); 1208 vok = VSIGN; 1209 break; 1210 case UINT64: 1211 uval = CHK_INF127(GET(u_int64_t)); 1212 vok = VUNSIGN; 1213 break; 1214 1215 case SIGLIST: 1216 default: 1217 /* nothing... */; 1218 } 1219 switch (vok) { 1220 case VSIGN: 1221 if (val < 0 && val < v->longestn) { 1222 v->longestn = val; 1223 fmtlen = iwidth(-val) + 1; 1224 if (fmtlen > v->width) 1225 v->width = fmtlen; 1226 } else if (val > 0 && val > v->longestp) { 1227 v->longestp = val; 1228 fmtlen = iwidth(val); 1229 if (fmtlen > v->width) 1230 v->width = fmtlen; 1231 } 1232 return; 1233 case VUNSIGN: 1234 if (uval > v->longestu) { 1235 v->longestu = uval; 1236 v->width = iwidth(uval); 1237 } 1238 return; 1239 case VPTR: 1240 fmtlen = 0; 1241 while (uval > 0) { 1242 uval >>= 4; 1243 fmtlen++; 1244 } 1245 if (fmtlen > v->width) 1246 v->width = fmtlen; 1247 return; 1248 } 1249 } 1250 1251 width = v->width; 1252 cp = ofmt + 1; 1253 fcp = v->fmt; 1254 if (v->flag & LJUST) 1255 *cp++ = '-'; 1256 *cp++ = '*'; 1257 while ((*cp++ = *fcp++) != '\0') 1258 continue; 1259 1260 switch (v->type) { 1261 case CHAR: 1262 (void)printf(ofmt, width, GET(char)); 1263 return; 1264 case UCHAR: 1265 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1266 return; 1267 case SHORT: 1268 (void)printf(ofmt, width, GET(short)); 1269 return; 1270 case USHORT: 1271 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1272 return; 1273 case INT: 1274 (void)printf(ofmt, width, GET(int)); 1275 return; 1276 case UINT: 1277 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1278 return; 1279 case LONG: 1280 (void)printf(ofmt, width, GET(long)); 1281 return; 1282 case ULONG: 1283 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1284 return; 1285 case KPTR: 1286 (void)printf(ofmt, width, GET(u_int64_t)); 1287 return; 1288 case KPTR24: 1289 (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff); 1290 return; 1291 case INT32: 1292 (void)printf(ofmt, width, GET(int32_t)); 1293 return; 1294 case UINT32: 1295 (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t))); 1296 return; 1297 case SIGLIST: 1298 { 1299 sigset_t *s = (sigset_t *)(void *)bp; 1300 size_t i; 1301 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1302 char buf[SIGSETSIZE * 8 + 1]; 1303 1304 for (i = 0; i < SIGSETSIZE; i++) 1305 (void)snprintf(&buf[i * 8], 9, "%.8x", 1306 s->__bits[(SIGSETSIZE - 1) - i]); 1307 1308 /* Skip leading zeroes */ 1309 for (i = 0; buf[i] == '0'; i++) 1310 continue; 1311 1312 if (buf[i] == '\0') 1313 i--; 1314 strprintorsetwidth(v, buf + i, mode); 1315 #undef SIGSETSIZE 1316 } 1317 return; 1318 case INT64: 1319 (void)printf(ofmt, width, GET(int64_t)); 1320 return; 1321 case UINT64: 1322 (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t))); 1323 return; 1324 default: 1325 errx(EXIT_FAILURE, "unknown type %d", v->type); 1326 } 1327 #undef GET 1328 #undef CHK_INF127 1329 } 1330 1331 void 1332 pvar(struct pinfo *pi, VARENT *ve, enum mode mode) 1333 { 1334 VAR *v = ve->var; 1335 char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki; 1336 1337 if ((v->flag & UAREA) && !pi->ki->p_uvalid) { 1338 if (mode == PRINTMODE) 1339 (void)printf("%*s", v->width, "-"); 1340 return; 1341 } 1342 1343 (void)printval(b + v->off, v, mode); 1344 } 1345 1346 void 1347 putimeval(struct pinfo *pi, VARENT *ve, enum mode mode) 1348 { 1349 VAR *v = ve->var; 1350 struct kinfo_proc2 *k = pi->ki; 1351 char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki; 1352 ulong secs = *(uint32_t *)(b + v->off); 1353 ulong usec = *(uint32_t *)(b + v->off + sizeof (uint32_t)); 1354 int fmtlen; 1355 1356 if (!k->p_uvalid) { 1357 if (mode == PRINTMODE) 1358 (void)printf("%*s", v->width, "-"); 1359 return; 1360 } 1361 1362 if (mode == WIDTHMODE) { 1363 if (secs == 0) 1364 /* non-zero so fmtlen is calculated at least once */ 1365 secs = 1; 1366 if (secs > v->longestu) { 1367 v->longestu = secs; 1368 if (secs <= 999) 1369 /* sss.ssssss */ 1370 fmtlen = iwidth(secs) + 6 + 1; 1371 else 1372 /* hh:mm:ss.ss */ 1373 fmtlen = iwidth((secs + 1) / SECSPERHOUR) 1374 + 2 + 1 + 2 + 1 + 2 + 1; 1375 if (fmtlen > v->width) 1376 v->width = fmtlen; 1377 } 1378 return; 1379 } 1380 1381 if (secs < 999) 1382 (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec); 1383 else { 1384 uint h, m; 1385 usec += 5000; 1386 if (usec >= 1000000) { 1387 usec -= 1000000; 1388 secs++; 1389 } 1390 m = secs / SECSPERMIN; 1391 secs -= m * SECSPERMIN; 1392 h = m / MINSPERHOUR; 1393 m -= h * MINSPERHOUR; 1394 (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs, 1395 usec / 10000u ); 1396 } 1397 } 1398 1399 void 1400 lname(struct pinfo *pi, VARENT *ve, enum mode mode) 1401 { 1402 struct kinfo_lwp *l = pi->li; 1403 VAR *v; 1404 1405 v = ve->var; 1406 if (l->l_name[0] != '\0') { 1407 strprintorsetwidth(v, l->l_name, mode); 1408 v->width = min(v->width, KI_LNAMELEN); 1409 } else { 1410 if (mode == PRINTMODE) 1411 (void)printf("%-*s", v->width, "-"); 1412 } 1413 } 1414