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