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