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