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