1 /* $NetBSD: print.c,v 1.129 2018/04/11 18:52:05 christos 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.129 2018/04/11 18:52:05 christos 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 char *buf; 931 932 v = ve->var; 933 if (l->l_wchan) { 934 if (l->l_wmesg[0]) { 935 strprintorsetwidth(v, l->l_wmesg, mode); 936 v->width = min(v->width, KI_WMESGLEN); 937 } else { 938 (void)asprintf(&buf, "%-*" PRIx64, v->width, 939 l->l_wchan); 940 if (buf == NULL) 941 err(EXIT_FAILURE, "%s", ""); 942 strprintorsetwidth(v, buf, mode); 943 v->width = min(v->width, KI_WMESGLEN); 944 free(buf); 945 } 946 } else { 947 if (mode == PRINTMODE) 948 (void)printf("%-*s", v->width, "-"); 949 } 950 } 951 952 #define pgtok(a) (((a)*(size_t)getpagesize())/1024) 953 954 void 955 vsize(struct pinfo *pi, VARENT *ve, enum mode mode) 956 { 957 struct kinfo_proc2 *k = pi->ki; 958 VAR *v; 959 960 v = ve->var; 961 intprintorsetwidth(v, pgtok(k->p_vm_msize), mode); 962 } 963 964 void 965 rssize(struct pinfo *pi, VARENT *ve, enum mode mode) 966 { 967 struct kinfo_proc2 *k = pi->ki; 968 VAR *v; 969 970 v = ve->var; 971 /* XXX don't have info about shared */ 972 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 973 } 974 975 void 976 p_rssize(struct pinfo *pi, VARENT *ve, enum mode mode) /* doesn't account for text */ 977 { 978 struct kinfo_proc2 *k = pi->ki; 979 VAR *v; 980 981 v = ve->var; 982 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 983 } 984 985 void 986 cpuid(struct pinfo *pi, VARENT *ve, enum mode mode) 987 { 988 struct kinfo_lwp *l = pi->li; 989 VAR *v; 990 991 v = ve->var; 992 intprintorsetwidth(v, l->l_cpuid, mode); 993 } 994 995 static void 996 cputime1(int32_t secs, int32_t psecs, VAR *v, enum mode mode) 997 { 998 int fmtlen; 999 1000 /* 1001 * round and scale to 100's 1002 */ 1003 psecs = (psecs + 5000) / 10000; 1004 secs += psecs / 100; 1005 psecs = psecs % 100; 1006 1007 if (mode == WIDTHMODE) { 1008 /* 1009 * Ugg, this is the only field where a value of 0 is longer 1010 * than the column title. 1011 * Use SECSPERMIN, because secs is divided by that when 1012 * passed to iwidth(). 1013 */ 1014 if (secs == 0) 1015 secs = SECSPERMIN; 1016 1017 if (secs > v->longestp) { 1018 v->longestp = secs; 1019 /* "+6" for the ":%02ld.%02ld" in the printf() below */ 1020 fmtlen = iwidth(secs / SECSPERMIN) + 6; 1021 if (fmtlen > v->width) 1022 v->width = fmtlen; 1023 } 1024 } else { 1025 (void)printf("%*ld:%02ld.%02ld", v->width - 6, 1026 (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN), 1027 (long)psecs); 1028 } 1029 } 1030 1031 void 1032 cputime(struct pinfo *pi, VARENT *ve, enum mode mode) 1033 { 1034 struct kinfo_proc2 *k = pi->ki; 1035 VAR *v; 1036 int32_t secs; 1037 int32_t psecs; /* "parts" of a second. first micro, then centi */ 1038 1039 v = ve->var; 1040 1041 /* 1042 * This counts time spent handling interrupts. We could 1043 * fix this, but it is not 100% trivial (and interrupt 1044 * time fractions only work on the sparc anyway). XXX 1045 */ 1046 secs = k->p_rtime_sec; 1047 psecs = k->p_rtime_usec; 1048 if (sumrusage) { 1049 secs += k->p_uctime_sec; 1050 psecs += k->p_uctime_usec; 1051 } 1052 1053 cputime1(secs, psecs, v, mode); 1054 } 1055 1056 void 1057 lcputime(struct pinfo *pi, VARENT *ve, enum mode mode) 1058 { 1059 struct kinfo_lwp *l = pi->li; 1060 VAR *v; 1061 int32_t secs; 1062 int32_t psecs; /* "parts" of a second. first micro, then centi */ 1063 1064 v = ve->var; 1065 1066 secs = l->l_rtime_sec; 1067 psecs = l->l_rtime_usec; 1068 1069 cputime1(secs, psecs, v, mode); 1070 } 1071 1072 void 1073 pcpu(struct pinfo *pi, VARENT *ve, enum mode mode) 1074 { 1075 VAR *v; 1076 double dbl; 1077 1078 v = ve->var; 1079 dbl = pi->pcpu; 1080 doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode); 1081 } 1082 1083 double 1084 getpmem(const struct kinfo_proc2 *k) 1085 { 1086 double fracmem; 1087 int szptudot; 1088 1089 if (!nlistread) 1090 donlist(); 1091 1092 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 1093 szptudot = uspace/getpagesize(); 1094 /* XXX don't have info about shared */ 1095 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 1096 return (100.0 * fracmem); 1097 } 1098 1099 void 1100 pmem(struct pinfo *pi, VARENT *ve, enum mode mode) 1101 { 1102 struct kinfo_proc2 *k = pi->ki; 1103 VAR *v; 1104 1105 v = ve->var; 1106 doubleprintorsetwidth(v, getpmem(k), 1, mode); 1107 } 1108 1109 void 1110 pagein(struct pinfo *pi, VARENT *ve, enum mode mode) 1111 { 1112 struct kinfo_proc2 *k = pi->ki; 1113 VAR *v; 1114 1115 v = ve->var; 1116 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 1117 } 1118 1119 void 1120 maxrss(struct pinfo *pi, VARENT *ve, enum mode mode) 1121 { 1122 VAR *v; 1123 1124 v = ve->var; 1125 /* No need to check width! */ 1126 if (mode == PRINTMODE) 1127 (void)printf("%*s", v->width, "-"); 1128 } 1129 1130 void 1131 tsize(struct pinfo *pi, VARENT *ve, enum mode mode) 1132 { 1133 struct kinfo_proc2 *k = pi->ki; 1134 VAR *v; 1135 1136 v = ve->var; 1137 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 1138 } 1139 1140 /* 1141 * Generic output routines. Print fields from various prototype 1142 * structures. 1143 */ 1144 static void 1145 printval(void *bp, VAR *v, enum mode mode) 1146 { 1147 static char ofmt[32] = "%"; 1148 int width, vok, fmtlen; 1149 const char *fcp; 1150 char *cp; 1151 int64_t val; 1152 u_int64_t uval; 1153 1154 val = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1155 uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1156 1157 /* 1158 * Note that the "INF127" check is nonsensical for types 1159 * that are or can be signed. 1160 */ 1161 #define GET(type) (*(type *)bp) 1162 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 1163 1164 #define VSIGN 1 1165 #define VUNSIGN 2 1166 #define VPTR 3 1167 1168 if (mode == WIDTHMODE) { 1169 vok = 0; 1170 switch (v->type) { 1171 case CHAR: 1172 val = GET(char); 1173 vok = VSIGN; 1174 break; 1175 case UCHAR: 1176 uval = CHK_INF127(GET(u_char)); 1177 vok = VUNSIGN; 1178 break; 1179 case SHORT: 1180 val = GET(short); 1181 vok = VSIGN; 1182 break; 1183 case USHORT: 1184 uval = CHK_INF127(GET(u_short)); 1185 vok = VUNSIGN; 1186 break; 1187 case INT32: 1188 val = GET(int32_t); 1189 vok = VSIGN; 1190 break; 1191 case INT: 1192 val = GET(int); 1193 vok = VSIGN; 1194 break; 1195 case UINT: 1196 case UINT32: 1197 uval = CHK_INF127(GET(u_int)); 1198 vok = VUNSIGN; 1199 break; 1200 case LONG: 1201 val = GET(long); 1202 vok = VSIGN; 1203 break; 1204 case ULONG: 1205 uval = CHK_INF127(GET(u_long)); 1206 vok = VUNSIGN; 1207 break; 1208 case KPTR: 1209 uval = GET(u_int64_t); 1210 vok = VPTR; 1211 break; 1212 case KPTR24: 1213 uval = GET(u_int64_t); 1214 uval &= 0xffffff; 1215 vok = VPTR; 1216 break; 1217 case INT64: 1218 val = GET(int64_t); 1219 vok = VSIGN; 1220 break; 1221 case UINT64: 1222 uval = CHK_INF127(GET(u_int64_t)); 1223 vok = VUNSIGN; 1224 break; 1225 1226 case SIGLIST: 1227 default: 1228 /* nothing... */; 1229 } 1230 switch (vok) { 1231 case VSIGN: 1232 if (val < 0 && val < v->longestn) { 1233 v->longestn = val; 1234 fmtlen = iwidth(-val) + 1; 1235 if (fmtlen > v->width) 1236 v->width = fmtlen; 1237 } else if (val > 0 && val > v->longestp) { 1238 v->longestp = val; 1239 fmtlen = iwidth(val); 1240 if (fmtlen > v->width) 1241 v->width = fmtlen; 1242 } 1243 return; 1244 case VUNSIGN: 1245 if (uval > v->longestu) { 1246 v->longestu = uval; 1247 v->width = iwidth(uval); 1248 } 1249 return; 1250 case VPTR: 1251 fmtlen = 0; 1252 while (uval > 0) { 1253 uval >>= 4; 1254 fmtlen++; 1255 } 1256 if (fmtlen > v->width) 1257 v->width = fmtlen; 1258 return; 1259 } 1260 } 1261 1262 width = v->width; 1263 cp = ofmt + 1; 1264 fcp = v->fmt; 1265 if (v->flag & LJUST) 1266 *cp++ = '-'; 1267 *cp++ = '*'; 1268 while ((*cp++ = *fcp++) != '\0') 1269 continue; 1270 1271 switch (v->type) { 1272 case CHAR: 1273 (void)printf(ofmt, width, GET(char)); 1274 return; 1275 case UCHAR: 1276 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1277 return; 1278 case SHORT: 1279 (void)printf(ofmt, width, GET(short)); 1280 return; 1281 case USHORT: 1282 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1283 return; 1284 case INT: 1285 (void)printf(ofmt, width, GET(int)); 1286 return; 1287 case UINT: 1288 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1289 return; 1290 case LONG: 1291 (void)printf(ofmt, width, GET(long)); 1292 return; 1293 case ULONG: 1294 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1295 return; 1296 case KPTR: 1297 (void)printf(ofmt, width, GET(u_int64_t)); 1298 return; 1299 case KPTR24: 1300 (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff); 1301 return; 1302 case INT32: 1303 (void)printf(ofmt, width, GET(int32_t)); 1304 return; 1305 case UINT32: 1306 (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t))); 1307 return; 1308 case SIGLIST: 1309 { 1310 sigset_t *s = (sigset_t *)(void *)bp; 1311 size_t i; 1312 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1313 char buf[SIGSETSIZE * 8 + 1]; 1314 1315 for (i = 0; i < SIGSETSIZE; i++) 1316 (void)snprintf(&buf[i * 8], 9, "%.8x", 1317 s->__bits[(SIGSETSIZE - 1) - i]); 1318 1319 /* Skip leading zeroes */ 1320 for (i = 0; buf[i] == '0'; i++) 1321 continue; 1322 1323 if (buf[i] == '\0') 1324 i--; 1325 strprintorsetwidth(v, buf + i, mode); 1326 #undef SIGSETSIZE 1327 } 1328 return; 1329 case INT64: 1330 (void)printf(ofmt, width, GET(int64_t)); 1331 return; 1332 case UINT64: 1333 (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t))); 1334 return; 1335 default: 1336 errx(EXIT_FAILURE, "unknown type %d", v->type); 1337 } 1338 #undef GET 1339 #undef CHK_INF127 1340 } 1341 1342 void 1343 pvar(struct pinfo *pi, VARENT *ve, enum mode mode) 1344 { 1345 VAR *v = ve->var; 1346 char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki; 1347 1348 if ((v->flag & UAREA) && !pi->ki->p_uvalid) { 1349 if (mode == PRINTMODE) 1350 (void)printf("%*s", v->width, "-"); 1351 return; 1352 } 1353 1354 (void)printval(b + v->off, v, mode); 1355 } 1356 1357 void 1358 putimeval(struct pinfo *pi, VARENT *ve, enum mode mode) 1359 { 1360 VAR *v = ve->var; 1361 struct kinfo_proc2 *k = pi->ki; 1362 char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki; 1363 ulong secs = *(uint32_t *)(b + v->off); 1364 ulong usec = *(uint32_t *)(b + v->off + sizeof (uint32_t)); 1365 int fmtlen; 1366 1367 if (!k->p_uvalid) { 1368 if (mode == PRINTMODE) 1369 (void)printf("%*s", v->width, "-"); 1370 return; 1371 } 1372 1373 if (mode == WIDTHMODE) { 1374 if (secs == 0) 1375 /* non-zero so fmtlen is calculated at least once */ 1376 secs = 1; 1377 if (secs > v->longestu) { 1378 v->longestu = secs; 1379 if (secs <= 999) 1380 /* sss.ssssss */ 1381 fmtlen = iwidth(secs) + 6 + 1; 1382 else 1383 /* hh:mm:ss.ss */ 1384 fmtlen = iwidth((secs + 1) / SECSPERHOUR) 1385 + 2 + 1 + 2 + 1 + 2 + 1; 1386 if (fmtlen > v->width) 1387 v->width = fmtlen; 1388 } 1389 return; 1390 } 1391 1392 if (secs < 999) 1393 (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec); 1394 else { 1395 uint h, m; 1396 usec += 5000; 1397 if (usec >= 1000000) { 1398 usec -= 1000000; 1399 secs++; 1400 } 1401 m = secs / SECSPERMIN; 1402 secs -= m * SECSPERMIN; 1403 h = m / MINSPERHOUR; 1404 m -= h * MINSPERHOUR; 1405 (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs, 1406 usec / 10000u ); 1407 } 1408 } 1409 1410 void 1411 lname(struct pinfo *pi, VARENT *ve, enum mode mode) 1412 { 1413 struct kinfo_lwp *l = pi->li; 1414 VAR *v; 1415 1416 v = ve->var; 1417 if (l->l_name[0] != '\0') { 1418 strprintorsetwidth(v, l->l_name, mode); 1419 v->width = min(v->width, KI_LNAMELEN); 1420 } else { 1421 if (mode == PRINTMODE) 1422 (void)printf("%-*s", v->width, "-"); 1423 } 1424 } 1425