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