1 /* $NetBSD: print.c,v 1.94 2005/06/27 00:46:04 christos 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.94 2005/06/27 00:46:04 christos 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 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0; 721 if (mode == WIDTHMODE) { 722 int fmtlen; 723 724 fmtlen = strlen(ttname) + noctty; 725 if (v->width < fmtlen) 726 v->width = fmtlen; 727 } else { 728 if (noctty) 729 (void)printf("%-*s-", v->width - 1, ttname); 730 else 731 (void)printf("%-*s", v->width, ttname); 732 } 733 } 734 } 735 736 void 737 longtname(void *arg, VARENT *ve, int mode) 738 { 739 struct kinfo_proc2 *k; 740 VAR *v; 741 dev_t dev; 742 const char *ttname; 743 744 k = arg; 745 v = ve->var; 746 dev = k->p_tdev; 747 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 748 if (mode == PRINTMODE) 749 (void)printf("%-*s", v->width, "?"); 750 else 751 if (v->width < 2) 752 v->width = 2; 753 } else { 754 strprintorsetwidth(v, ttname, mode); 755 } 756 } 757 758 void 759 started(void *arg, VARENT *ve, int mode) 760 { 761 struct kinfo_proc2 *k; 762 VAR *v; 763 time_t startt; 764 struct tm *tp; 765 char buf[100], *cp; 766 767 k = arg; 768 v = ve->var; 769 if (!k->p_uvalid) { 770 if (mode == PRINTMODE) 771 (void)printf("%*s", v->width, "-"); 772 return; 773 } 774 775 startt = k->p_ustart_sec; 776 tp = localtime(&startt); 777 if (now == 0) 778 (void)time(&now); 779 if (now - k->p_ustart_sec < SECSPERDAY) 780 /* I *hate* SCCS... */ 781 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 782 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 783 /* I *hate* SCCS... */ 784 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 785 else 786 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 787 /* %e and %l can start with a space. */ 788 cp = buf; 789 if (*cp == ' ') 790 cp++; 791 strprintorsetwidth(v, cp, mode); 792 } 793 794 void 795 lstarted(void *arg, VARENT *ve, int mode) 796 { 797 struct kinfo_proc2 *k; 798 VAR *v; 799 time_t startt; 800 char buf[100]; 801 802 k = arg; 803 v = ve->var; 804 if (!k->p_uvalid) { 805 /* 806 * Minimum width is less than header - we don't 807 * need to check it every time. 808 */ 809 if (mode == PRINTMODE) 810 (void)printf("%*s", v->width, "-"); 811 return; 812 } 813 startt = k->p_ustart_sec; 814 815 /* assume all times are the same length */ 816 if (mode != WIDTHMODE || v->width == 0) { 817 (void)strftime(buf, sizeof(buf) -1, "%c", 818 localtime(&startt)); 819 strprintorsetwidth(v, buf, mode); 820 } 821 } 822 823 void 824 elapsed(void *arg, VARENT *ve, int mode) 825 { 826 struct kinfo_proc2 *k; 827 VAR *v; 828 int32_t origseconds, secs, mins, hours, days; 829 int fmtlen, printed_something; 830 831 k = arg; 832 v = ve->var; 833 if (k->p_uvalid == 0) { 834 origseconds = 0; 835 } else { 836 if (now == 0) 837 (void)time(&now); 838 origseconds = now - k->p_ustart_sec; 839 if (origseconds < 0) { 840 /* 841 * Don't try to be fancy if the machine's 842 * clock has been rewound to before the 843 * process "started". 844 */ 845 origseconds = 0; 846 } 847 } 848 849 secs = origseconds; 850 mins = secs / SECSPERMIN; 851 secs %= SECSPERMIN; 852 hours = mins / MINSPERHOUR; 853 mins %= MINSPERHOUR; 854 days = hours / HOURSPERDAY; 855 hours %= HOURSPERDAY; 856 857 if (mode == WIDTHMODE) { 858 if (origseconds == 0) 859 /* non-zero so fmtlen is calculated at least once */ 860 origseconds = 1; 861 862 if (origseconds > v->longestp) { 863 v->longestp = origseconds; 864 865 if (days > 0) { 866 /* +9 for "-hh:mm:ss" */ 867 fmtlen = iwidth(days) + 9; 868 } else if (hours > 0) { 869 /* +6 for "mm:ss" */ 870 fmtlen = iwidth(hours) + 6; 871 } else { 872 /* +3 for ":ss" */ 873 fmtlen = iwidth(mins) + 3; 874 } 875 876 if (fmtlen > v->width) 877 v->width = fmtlen; 878 } 879 } else { 880 printed_something = 0; 881 fmtlen = v->width; 882 883 if (days > 0) { 884 (void)printf("%*d", fmtlen - 9, days); 885 printed_something = 1; 886 } else if (fmtlen > 9) { 887 (void)printf("%*s", fmtlen - 9, ""); 888 } 889 if (fmtlen > 9) 890 fmtlen = 9; 891 892 if (printed_something) { 893 (void)printf("-%.*d", fmtlen - 7, hours); 894 printed_something = 1; 895 } else if (hours > 0) { 896 (void)printf("%*d", fmtlen - 6, hours); 897 printed_something = 1; 898 } else if (fmtlen > 6) { 899 (void)printf("%*s", fmtlen - 6, ""); 900 } 901 if (fmtlen > 6) 902 fmtlen = 6; 903 904 /* Don't need to set fmtlen or printed_something any more... */ 905 if (printed_something) { 906 (void)printf(":%.*d", fmtlen - 4, mins); 907 } else if (mins > 0) { 908 (void)printf("%*d", fmtlen - 3, mins); 909 } else if (fmtlen > 3) { 910 (void)printf("%*s", fmtlen - 3, "0"); 911 } 912 913 (void)printf(":%.2d", secs); 914 } 915 } 916 917 void 918 wchan(void *arg, VARENT *ve, int mode) 919 { 920 struct kinfo_lwp *l; 921 VAR *v; 922 char *buf; 923 924 l = arg; 925 v = ve->var; 926 if (l->l_wchan) { 927 if (l->l_wmesg) { 928 strprintorsetwidth(v, l->l_wmesg, mode); 929 v->width = min(v->width, KI_WMESGLEN); 930 } else { 931 (void)asprintf(&buf, "%-*" PRIx64, v->width, 932 l->l_wchan); 933 if (buf == NULL) 934 err(1, "%s", ""); 935 strprintorsetwidth(v, buf, mode); 936 v->width = min(v->width, KI_WMESGLEN); 937 free(buf); 938 } 939 } else { 940 if (mode == PRINTMODE) 941 (void)printf("%-*s", v->width, "-"); 942 } 943 } 944 945 #define pgtok(a) (((a)*getpagesize())/1024) 946 947 void 948 vsize(void *arg, VARENT *ve, int mode) 949 { 950 struct kinfo_proc2 *k; 951 VAR *v; 952 953 k = arg; 954 v = ve->var; 955 intprintorsetwidth(v, 956 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode); 957 } 958 959 void 960 rssize(void *arg, VARENT *ve, int mode) 961 { 962 struct kinfo_proc2 *k; 963 VAR *v; 964 965 k = arg; 966 v = ve->var; 967 /* XXX don't have info about shared */ 968 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 969 } 970 971 void 972 p_rssize(void *arg, VARENT *ve, int mode) /* doesn't account for text */ 973 { 974 struct kinfo_proc2 *k; 975 VAR *v; 976 977 k = arg; 978 v = ve->var; 979 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 980 } 981 982 void 983 cputime(void *arg, VARENT *ve, int mode) 984 { 985 struct kinfo_proc2 *k; 986 VAR *v; 987 int32_t secs; 988 int32_t psecs; /* "parts" of a second. first micro, then centi */ 989 int fmtlen; 990 991 k = arg; 992 v = ve->var; 993 if (P_ZOMBIE(k) || k->p_uvalid == 0) { 994 secs = 0; 995 psecs = 0; 996 } else { 997 /* 998 * This counts time spent handling interrupts. We could 999 * fix this, but it is not 100% trivial (and interrupt 1000 * time fractions only work on the sparc anyway). XXX 1001 */ 1002 secs = k->p_rtime_sec; 1003 psecs = k->p_rtime_usec; 1004 if (sumrusage) { 1005 secs += k->p_uctime_sec; 1006 psecs += k->p_uctime_usec; 1007 } 1008 /* 1009 * round and scale to 100's 1010 */ 1011 psecs = (psecs + 5000) / 10000; 1012 secs += psecs / 100; 1013 psecs = psecs % 100; 1014 } 1015 if (mode == WIDTHMODE) { 1016 /* 1017 * Ugg, this is the only field where a value of 0 is longer 1018 * than the column title. 1019 * Use SECSPERMIN, because secs is divided by that when 1020 * passed to iwidth(). 1021 */ 1022 if (secs == 0) 1023 secs = SECSPERMIN; 1024 1025 if (secs > v->longestp) { 1026 v->longestp = secs; 1027 /* "+6" for the ":%02ld.%02ld" in the printf() below */ 1028 fmtlen = iwidth(secs / SECSPERMIN) + 6; 1029 if (fmtlen > v->width) 1030 v->width = fmtlen; 1031 } 1032 } else { 1033 (void)printf("%*ld:%02ld.%02ld", v->width - 6, 1034 (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN), 1035 (long)psecs); 1036 } 1037 } 1038 1039 double 1040 getpcpu(k) 1041 const struct kinfo_proc2 *k; 1042 { 1043 static int failure; 1044 1045 if (!nlistread) 1046 failure = (kd) ? donlist() : 1; 1047 if (failure) 1048 return (0.0); 1049 1050 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 1051 1052 /* XXX - I don't like this */ 1053 if (k->p_swtime == 0 || (k->p_flag & L_INMEM) == 0 || 1054 k->p_stat == SZOMB) 1055 return (0.0); 1056 if (rawcpu) 1057 return (100.0 * fxtofl(k->p_pctcpu)); 1058 return (100.0 * fxtofl(k->p_pctcpu) / 1059 (1.0 - exp(k->p_swtime * log(ccpu)))); 1060 } 1061 1062 void 1063 pcpu(void *arg, VARENT *ve, int mode) 1064 { 1065 struct kinfo_proc2 *k; 1066 VAR *v; 1067 1068 k = arg; 1069 v = ve->var; 1070 doubleprintorsetwidth(v, getpcpu(k), 1, mode); 1071 } 1072 1073 double 1074 getpmem(k) 1075 const struct kinfo_proc2 *k; 1076 { 1077 static int failure; 1078 double fracmem; 1079 int szptudot; 1080 1081 if (!nlistread) 1082 failure = (kd) ? donlist() : 1; 1083 if (failure) 1084 return (0.0); 1085 1086 if ((k->p_flag & L_INMEM) == 0) 1087 return (0.0); 1088 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 1089 szptudot = uspace/getpagesize(); 1090 /* XXX don't have info about shared */ 1091 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 1092 return (100.0 * fracmem); 1093 } 1094 1095 void 1096 pmem(void *arg, VARENT *ve, int mode) 1097 { 1098 struct kinfo_proc2 *k; 1099 VAR *v; 1100 1101 k = arg; 1102 v = ve->var; 1103 doubleprintorsetwidth(v, getpmem(k), 1, mode); 1104 } 1105 1106 void 1107 pagein(void *arg, VARENT *ve, 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(void *arg, VARENT *ve, int mode) 1119 { 1120 VAR *v; 1121 1122 v = ve->var; 1123 /* No need to check width! */ 1124 if (mode == PRINTMODE) 1125 (void)printf("%*s", v->width, "-"); 1126 } 1127 1128 void 1129 tsize(void *arg, VARENT *ve, int mode) 1130 { 1131 struct kinfo_proc2 *k; 1132 VAR *v; 1133 1134 k = arg; 1135 v = ve->var; 1136 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 1137 } 1138 1139 /* 1140 * Generic output routines. Print fields from various prototype 1141 * structures. 1142 */ 1143 static void 1144 printval(bp, v, mode) 1145 void *bp; 1146 VAR *v; 1147 int mode; 1148 { 1149 static char ofmt[32] = "%"; 1150 int width, vok, fmtlen; 1151 const char *fcp; 1152 char *cp; 1153 int64_t val; 1154 u_int64_t uval; 1155 1156 val = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1157 uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1158 1159 /* 1160 * Note that the "INF127" check is nonsensical for types 1161 * that are or can be signed. 1162 */ 1163 #define GET(type) (*(type *)bp) 1164 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 1165 1166 #define VSIGN 1 1167 #define VUNSIGN 2 1168 #define VPTR 3 1169 1170 if (mode == WIDTHMODE) { 1171 vok = 0; 1172 switch (v->type) { 1173 case CHAR: 1174 val = GET(char); 1175 vok = VSIGN; 1176 break; 1177 case UCHAR: 1178 uval = CHK_INF127(GET(u_char)); 1179 vok = VUNSIGN; 1180 break; 1181 case SHORT: 1182 val = GET(short); 1183 vok = VSIGN; 1184 break; 1185 case USHORT: 1186 uval = CHK_INF127(GET(u_short)); 1187 vok = VUNSIGN; 1188 break; 1189 case INT32: 1190 val = GET(int32_t); 1191 vok = VSIGN; 1192 break; 1193 case INT: 1194 val = GET(int); 1195 vok = VSIGN; 1196 break; 1197 case UINT: 1198 case UINT32: 1199 uval = CHK_INF127(GET(u_int)); 1200 vok = VUNSIGN; 1201 break; 1202 case LONG: 1203 val = GET(long); 1204 vok = VSIGN; 1205 break; 1206 case ULONG: 1207 uval = CHK_INF127(GET(u_long)); 1208 vok = VUNSIGN; 1209 break; 1210 case KPTR: 1211 uval = GET(u_int64_t); 1212 vok = VPTR; 1213 break; 1214 case KPTR24: 1215 uval = GET(u_int64_t); 1216 uval &= 0xffffff; 1217 vok = VPTR; 1218 break; 1219 case INT64: 1220 val = GET(int64_t); 1221 vok = VSIGN; 1222 break; 1223 case UINT64: 1224 uval = CHK_INF127(GET(u_int64_t)); 1225 vok = VUNSIGN; 1226 break; 1227 1228 case SIGLIST: 1229 default: 1230 /* nothing... */; 1231 } 1232 switch (vok) { 1233 case VSIGN: 1234 if (val < 0 && val < v->longestn) { 1235 v->longestn = val; 1236 fmtlen = iwidth(-val) + 1; 1237 if (fmtlen > v->width) 1238 v->width = fmtlen; 1239 } else if (val > 0 && val > v->longestp) { 1240 v->longestp = val; 1241 fmtlen = iwidth(val); 1242 if (fmtlen > v->width) 1243 v->width = fmtlen; 1244 } 1245 return; 1246 case VUNSIGN: 1247 if (uval > v->longestu) { 1248 v->longestu = uval; 1249 v->width = iwidth(uval); 1250 } 1251 return; 1252 case VPTR: 1253 fmtlen = 0; 1254 while (uval > 0) { 1255 uval >>= 4; 1256 fmtlen++; 1257 } 1258 if (fmtlen > v->width) 1259 v->width = fmtlen; 1260 return; 1261 } 1262 } 1263 1264 width = v->width; 1265 cp = ofmt + 1; 1266 fcp = v->fmt; 1267 if (v->flag & LJUST) 1268 *cp++ = '-'; 1269 *cp++ = '*'; 1270 while ((*cp++ = *fcp++) != '\0') 1271 continue; 1272 1273 switch (v->type) { 1274 case CHAR: 1275 (void)printf(ofmt, width, GET(char)); 1276 return; 1277 case UCHAR: 1278 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1279 return; 1280 case SHORT: 1281 (void)printf(ofmt, width, GET(short)); 1282 return; 1283 case USHORT: 1284 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1285 return; 1286 case INT: 1287 (void)printf(ofmt, width, GET(int)); 1288 return; 1289 case UINT: 1290 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1291 return; 1292 case LONG: 1293 (void)printf(ofmt, width, GET(long)); 1294 return; 1295 case ULONG: 1296 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1297 return; 1298 case KPTR: 1299 (void)printf(ofmt, width, GET(u_int64_t)); 1300 return; 1301 case KPTR24: 1302 (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff); 1303 return; 1304 case INT32: 1305 (void)printf(ofmt, width, GET(int32_t)); 1306 return; 1307 case UINT32: 1308 (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t))); 1309 return; 1310 case SIGLIST: 1311 { 1312 sigset_t *s = (sigset_t *)(void *)bp; 1313 size_t i; 1314 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1315 char buf[SIGSETSIZE * 8 + 1]; 1316 1317 for (i = 0; i < SIGSETSIZE; i++) 1318 (void)snprintf(&buf[i * 8], 9, "%.8x", 1319 s->__bits[(SIGSETSIZE - 1) - i]); 1320 1321 /* Skip leading zeroes */ 1322 for (i = 0; buf[i] == '0'; i++) 1323 continue; 1324 1325 if (buf[i] == '\0') 1326 i--; 1327 strprintorsetwidth(v, buf + i, mode); 1328 #undef SIGSETSIZE 1329 } 1330 return; 1331 case INT64: 1332 (void)printf(ofmt, width, GET(int64_t)); 1333 return; 1334 case UINT64: 1335 (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t))); 1336 return; 1337 default: 1338 errx(1, "unknown type %d", v->type); 1339 } 1340 #undef GET 1341 #undef CHK_INF127 1342 } 1343 1344 void 1345 pvar(void *arg, VARENT *ve, int mode) 1346 { 1347 VAR *v; 1348 1349 v = ve->var; 1350 if (v->flag & UAREA && !((struct kinfo_proc2 *)arg)->p_uvalid) { 1351 if (mode == PRINTMODE) 1352 (void)printf("%*s", v->width, "-"); 1353 return; 1354 } 1355 1356 (void)printval((char *)arg + v->off, v, mode); 1357 } 1358 1359 void 1360 putimeval(void *arg, VARENT *ve, int mode) 1361 { 1362 VAR *v = ve->var; 1363 struct kinfo_proc2 *k = arg; 1364 ulong secs = *(uint32_t *)((char *)arg + v->off); 1365 ulong usec = *(uint32_t *)((char *)arg + v->off + sizeof (uint32_t)); 1366 int fmtlen; 1367 1368 if (!k->p_uvalid) { 1369 if (mode == PRINTMODE) 1370 (void)printf("%*s", v->width, "-"); 1371 return; 1372 } 1373 1374 if (mode == WIDTHMODE) { 1375 if (secs == 0) 1376 /* non-zero so fmtlen is calculated at least once */ 1377 secs = 1; 1378 if (secs > v->longestu) { 1379 v->longestu = secs; 1380 if (secs <= 999) 1381 /* sss.ssssss */ 1382 fmtlen = iwidth(secs) + 6 + 1; 1383 else 1384 /* hh:mm:ss.ss */ 1385 fmtlen = iwidth((secs + 1) / SECSPERHOUR) 1386 + 2 + 1 + 2 + 1 + 2 + 1; 1387 if (fmtlen > v->width) 1388 v->width = fmtlen; 1389 } 1390 return; 1391 } 1392 1393 if (secs < 999) 1394 (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec); 1395 else { 1396 uint h, m; 1397 usec += 5000; 1398 if (usec >= 1000000) { 1399 usec -= 1000000; 1400 secs++; 1401 } 1402 m = secs / SECSPERMIN; 1403 secs -= m * SECSPERMIN; 1404 h = m / MINSPERHOUR; 1405 m -= h * MINSPERHOUR; 1406 (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs, 1407 usec / 10000u ); 1408 } 1409 } 1410