1 /* $NetBSD: print.c,v 1.107 2008/12/28 19:50:22 christos 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.107 2008/12/28 19:50:22 christos 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 return; 389 } 390 391 for (i = 0; i < ki->p_ngroups; i++) { 392 (void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]); 393 if (i) 394 fmt_putc(' ', &left); 395 for (p = &buf[0]; *p; p++) 396 fmt_putc(*p, &left); 397 } 398 399 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 400 (void)printf("%*s", left, ""); 401 } 402 403 void 404 groupnames(void *arg, VARENT *ve, int mode) 405 { 406 struct kinfo_proc2 *ki; 407 VAR *v; 408 int left, i; 409 const char *p; 410 411 if (mode == WIDTHMODE) 412 return; 413 414 ki = arg; 415 v = ve->var; 416 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 417 if (SIMPLEQ_NEXT(ve, next) == NULL) { 418 left = termwidth - (totwidth - v->width); 419 if (left < 1) /* already wrapped, just use std width */ 420 left = v->width; 421 } else 422 left = v->width; 423 } else 424 left = -1; 425 426 if (ki->p_ngroups == 0) { 427 fmt_putc('-', &left); 428 return; 429 } 430 431 for (i = 0; i < ki->p_ngroups; i++) { 432 if (i) 433 fmt_putc(' ', &left); 434 for (p = group_from_gid(ki->p_groups[i], 0); *p; p++) 435 fmt_putc(*p, &left); 436 } 437 438 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 439 (void)printf("%*s", left, ""); 440 } 441 442 void 443 ucomm(void *arg, VARENT *ve, int mode) 444 { 445 struct kinfo_proc2 *k; 446 VAR *v; 447 448 k = arg; 449 v = ve->var; 450 strprintorsetwidth(v, k->p_comm, mode); 451 } 452 453 void 454 emul(void *arg, VARENT *ve, int mode) 455 { 456 struct kinfo_proc2 *k; 457 VAR *v; 458 459 k = arg; 460 v = ve->var; 461 strprintorsetwidth(v, k->p_ename, mode); 462 } 463 464 void 465 logname(void *arg, VARENT *ve, int mode) 466 { 467 struct kinfo_proc2 *k; 468 VAR *v; 469 470 k = arg; 471 v = ve->var; 472 strprintorsetwidth(v, k->p_login, mode); 473 } 474 475 void 476 state(void *arg, VARENT *ve, 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 *cp = 'R'; 506 break; 507 508 case LSONPROC: 509 *cp = 'O'; 510 break; 511 512 case LSZOMB: 513 *cp = 'Z'; 514 is_zombie = 1; 515 break; 516 517 case LSSUSPENDED: 518 *cp = 'U'; 519 break; 520 521 default: 522 *cp = '?'; 523 } 524 cp++; 525 if (flag & L_INMEM) { 526 } else 527 *cp++ = 'W'; 528 if (k->p_nice < NZERO) 529 *cp++ = '<'; 530 else if (k->p_nice > NZERO) 531 *cp++ = 'N'; 532 if (flag & P_TRACED) 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(void *arg, VARENT *ve, int mode) 557 { 558 struct kinfo_lwp *k; 559 int flag, is_zombie; 560 char *cp; 561 VAR *v; 562 char buf[16]; 563 564 k = arg; 565 is_zombie = 0; 566 v = ve->var; 567 flag = k->l_flag; 568 cp = buf; 569 570 switch (k->l_stat) { 571 572 case LSSTOP: 573 *cp = 'T'; 574 break; 575 576 case LSSLEEP: 577 if (flag & L_SINTR) /* interruptible (long) */ 578 *cp = k->l_slptime >= maxslp ? 'I' : 'S'; 579 else 580 *cp = 'D'; 581 break; 582 583 case LSRUN: 584 case LSIDL: 585 case LSONPROC: 586 *cp = 'R'; 587 break; 588 589 case LSZOMB: 590 case LSDEAD: 591 *cp = 'Z'; 592 is_zombie = 1; 593 break; 594 595 case LSSUSPENDED: 596 *cp = 'U'; 597 break; 598 599 default: 600 *cp = '?'; 601 } 602 cp++; 603 if (flag & L_INMEM) { 604 } else 605 *cp++ = 'W'; 606 if (k->l_holdcnt) 607 *cp++ = 'L'; 608 if (flag & L_DETACHED) 609 *cp++ = '-'; 610 *cp = '\0'; 611 strprintorsetwidth(v, buf, mode); 612 } 613 614 void 615 pnice(void *arg, VARENT *ve, int mode) 616 { 617 struct kinfo_proc2 *k; 618 VAR *v; 619 620 k = arg; 621 v = ve->var; 622 intprintorsetwidth(v, k->p_nice - NZERO, mode); 623 } 624 625 void 626 pri(void *arg, VARENT *ve, int mode) 627 { 628 struct kinfo_lwp *l; 629 VAR *v; 630 631 l = arg; 632 v = ve->var; 633 intprintorsetwidth(v, l->l_priority, mode); 634 } 635 636 void 637 uname(void *arg, VARENT *ve, int mode) 638 { 639 struct kinfo_proc2 *k; 640 VAR *v; 641 642 k = arg; 643 v = ve->var; 644 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode); 645 } 646 647 void 648 runame(void *arg, VARENT *ve, int mode) 649 { 650 struct kinfo_proc2 *k; 651 VAR *v; 652 653 k = arg; 654 v = ve->var; 655 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode); 656 } 657 658 void 659 svuname(void *arg, VARENT *ve, int mode) 660 { 661 struct kinfo_proc2 *k; 662 VAR *v; 663 664 k = arg; 665 v = ve->var; 666 strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode); 667 } 668 669 void 670 gname(void *arg, VARENT *ve, int mode) 671 { 672 struct kinfo_proc2 *k; 673 VAR *v; 674 675 k = arg; 676 v = ve->var; 677 strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode); 678 } 679 680 void 681 rgname(void *arg, VARENT *ve, int mode) 682 { 683 struct kinfo_proc2 *k; 684 VAR *v; 685 686 k = arg; 687 v = ve->var; 688 strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode); 689 } 690 691 void 692 svgname(void *arg, VARENT *ve, int mode) 693 { 694 struct kinfo_proc2 *k; 695 VAR *v; 696 697 k = arg; 698 v = ve->var; 699 strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode); 700 } 701 702 void 703 tdev(void *arg, VARENT *ve, int mode) 704 { 705 struct kinfo_proc2 *k; 706 VAR *v; 707 dev_t dev; 708 char buff[16]; 709 710 k = arg; 711 v = ve->var; 712 dev = k->p_tdev; 713 if (dev == NODEV) { 714 if (mode == PRINTMODE) 715 (void)printf("%*s", v->width, "?"); 716 else 717 if (v->width < 2) 718 v->width = 2; 719 } else { 720 (void)snprintf(buff, sizeof(buff), 721 "%lld/%lld", (long long)major(dev), (long long)minor(dev)); 722 strprintorsetwidth(v, buff, mode); 723 } 724 } 725 726 void 727 tname(void *arg, VARENT *ve, int mode) 728 { 729 struct kinfo_proc2 *k; 730 VAR *v; 731 dev_t dev; 732 const char *ttname; 733 int noctty; 734 735 k = arg; 736 v = ve->var; 737 dev = k->p_tdev; 738 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 739 if (mode == PRINTMODE) 740 (void)printf("%-*s", v->width, "?"); 741 else 742 if (v->width < 2) 743 v->width = 2; 744 } else { 745 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0; 746 if (mode == WIDTHMODE) { 747 int fmtlen; 748 749 fmtlen = strlen(ttname) + noctty; 750 if (v->width < fmtlen) 751 v->width = fmtlen; 752 } else { 753 if (noctty) 754 (void)printf("%-*s-", v->width - 1, ttname); 755 else 756 (void)printf("%-*s", v->width, ttname); 757 } 758 } 759 } 760 761 void 762 longtname(void *arg, VARENT *ve, int mode) 763 { 764 struct kinfo_proc2 *k; 765 VAR *v; 766 dev_t dev; 767 const char *ttname; 768 769 k = arg; 770 v = ve->var; 771 dev = k->p_tdev; 772 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 773 if (mode == PRINTMODE) 774 (void)printf("%-*s", v->width, "?"); 775 else 776 if (v->width < 2) 777 v->width = 2; 778 } else { 779 strprintorsetwidth(v, ttname, mode); 780 } 781 } 782 783 void 784 started(void *arg, VARENT *ve, int mode) 785 { 786 struct kinfo_proc2 *k; 787 VAR *v; 788 time_t startt; 789 struct tm *tp; 790 char buf[100], *cp; 791 792 k = arg; 793 v = ve->var; 794 if (!k->p_uvalid) { 795 if (mode == PRINTMODE) 796 (void)printf("%*s", v->width, "-"); 797 return; 798 } 799 800 startt = k->p_ustart_sec; 801 tp = localtime(&startt); 802 if (now == 0) 803 (void)time(&now); 804 if (now - k->p_ustart_sec < SECSPERDAY) 805 /* I *hate* SCCS... */ 806 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 807 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 808 /* I *hate* SCCS... */ 809 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 810 else 811 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 812 /* %e and %l can start with a space. */ 813 cp = buf; 814 if (*cp == ' ') 815 cp++; 816 strprintorsetwidth(v, cp, mode); 817 } 818 819 void 820 lstarted(void *arg, VARENT *ve, int mode) 821 { 822 struct kinfo_proc2 *k; 823 VAR *v; 824 time_t startt; 825 char buf[100]; 826 827 k = arg; 828 v = ve->var; 829 if (!k->p_uvalid) { 830 /* 831 * Minimum width is less than header - we don't 832 * need to check it every time. 833 */ 834 if (mode == PRINTMODE) 835 (void)printf("%*s", v->width, "-"); 836 return; 837 } 838 startt = k->p_ustart_sec; 839 840 /* assume all times are the same length */ 841 if (mode != WIDTHMODE || v->width == 0) { 842 (void)strftime(buf, sizeof(buf) -1, "%c", 843 localtime(&startt)); 844 strprintorsetwidth(v, buf, mode); 845 } 846 } 847 848 void 849 elapsed(void *arg, VARENT *ve, int mode) 850 { 851 struct kinfo_proc2 *k; 852 VAR *v; 853 int32_t origseconds, secs, mins, hours, days; 854 int fmtlen, printed_something; 855 856 k = arg; 857 v = ve->var; 858 if (k->p_uvalid == 0) { 859 origseconds = 0; 860 } else { 861 if (now == 0) 862 (void)time(&now); 863 origseconds = now - k->p_ustart_sec; 864 if (origseconds < 0) { 865 /* 866 * Don't try to be fancy if the machine's 867 * clock has been rewound to before the 868 * process "started". 869 */ 870 origseconds = 0; 871 } 872 } 873 874 secs = origseconds; 875 mins = secs / SECSPERMIN; 876 secs %= SECSPERMIN; 877 hours = mins / MINSPERHOUR; 878 mins %= MINSPERHOUR; 879 days = hours / HOURSPERDAY; 880 hours %= HOURSPERDAY; 881 882 if (mode == WIDTHMODE) { 883 if (origseconds == 0) 884 /* non-zero so fmtlen is calculated at least once */ 885 origseconds = 1; 886 887 if (origseconds > v->longestp) { 888 v->longestp = origseconds; 889 890 if (days > 0) { 891 /* +9 for "-hh:mm:ss" */ 892 fmtlen = iwidth(days) + 9; 893 } else if (hours > 0) { 894 /* +6 for "mm:ss" */ 895 fmtlen = iwidth(hours) + 6; 896 } else { 897 /* +3 for ":ss" */ 898 fmtlen = iwidth(mins) + 3; 899 } 900 901 if (fmtlen > v->width) 902 v->width = fmtlen; 903 } 904 } else { 905 printed_something = 0; 906 fmtlen = v->width; 907 908 if (days > 0) { 909 (void)printf("%*d", fmtlen - 9, days); 910 printed_something = 1; 911 } else if (fmtlen > 9) { 912 (void)printf("%*s", fmtlen - 9, ""); 913 } 914 if (fmtlen > 9) 915 fmtlen = 9; 916 917 if (printed_something) { 918 (void)printf("-%.*d", fmtlen - 7, hours); 919 printed_something = 1; 920 } else if (hours > 0) { 921 (void)printf("%*d", fmtlen - 6, hours); 922 printed_something = 1; 923 } else if (fmtlen > 6) { 924 (void)printf("%*s", fmtlen - 6, ""); 925 } 926 if (fmtlen > 6) 927 fmtlen = 6; 928 929 /* Don't need to set fmtlen or printed_something any more... */ 930 if (printed_something) { 931 (void)printf(":%.*d", fmtlen - 4, mins); 932 } else if (mins > 0) { 933 (void)printf("%*d", fmtlen - 3, mins); 934 } else if (fmtlen > 3) { 935 (void)printf("%*s", fmtlen - 3, "0"); 936 } 937 938 (void)printf(":%.2d", secs); 939 } 940 } 941 942 void 943 wchan(void *arg, VARENT *ve, int mode) 944 { 945 struct kinfo_lwp *l; 946 VAR *v; 947 char *buf; 948 949 l = arg; 950 v = ve->var; 951 if (l->l_wchan) { 952 if (l->l_wmesg) { 953 strprintorsetwidth(v, l->l_wmesg, mode); 954 v->width = min(v->width, KI_WMESGLEN); 955 } else { 956 (void)asprintf(&buf, "%-*" PRIx64, v->width, 957 l->l_wchan); 958 if (buf == NULL) 959 err(1, "%s", ""); 960 strprintorsetwidth(v, buf, mode); 961 v->width = min(v->width, KI_WMESGLEN); 962 free(buf); 963 } 964 } else { 965 if (mode == PRINTMODE) 966 (void)printf("%-*s", v->width, "-"); 967 } 968 } 969 970 #define pgtok(a) (((a)*getpagesize())/1024) 971 972 void 973 vsize(void *arg, VARENT *ve, int mode) 974 { 975 struct kinfo_proc2 *k; 976 VAR *v; 977 978 k = arg; 979 v = ve->var; 980 intprintorsetwidth(v, 981 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode); 982 } 983 984 void 985 rssize(void *arg, VARENT *ve, int mode) 986 { 987 struct kinfo_proc2 *k; 988 VAR *v; 989 990 k = arg; 991 v = ve->var; 992 /* XXX don't have info about shared */ 993 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 994 } 995 996 void 997 p_rssize(void *arg, VARENT *ve, int mode) /* doesn't account for text */ 998 { 999 struct kinfo_proc2 *k; 1000 VAR *v; 1001 1002 k = arg; 1003 v = ve->var; 1004 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 1005 } 1006 1007 void 1008 setncpu(void) 1009 { 1010 int mib[2]; 1011 size_t size; 1012 1013 mib[0] = CTL_HW; 1014 mib[1] = HW_NCPU; 1015 size = sizeof(ncpu); 1016 if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) { 1017 ncpu = 0; 1018 return; 1019 } 1020 cp_id = malloc(sizeof(cp_id[0]) * ncpu); 1021 if (cp_id == NULL) 1022 err(1, NULL); 1023 mib[0] = CTL_KERN; 1024 mib[1] = KERN_CP_ID; 1025 size = sizeof(cp_id[0]) * ncpu; 1026 if (sysctl(mib, 2, cp_id, &size, NULL, 0) == -1) 1027 ncpu = 0; 1028 } 1029 1030 static int 1031 get_cpunum(u_int64_t id) 1032 { 1033 int i = 0; 1034 for (i = 0; i < ncpu; i++) 1035 if (id == cp_id[i]) 1036 return i; 1037 return -1; 1038 } 1039 1040 void 1041 cpuid(void *arg, VARENT *ve, int mode) 1042 { 1043 struct kinfo_lwp *l; 1044 VAR *v; 1045 1046 l = arg; 1047 v = ve->var; 1048 intprintorsetwidth(v, get_cpunum(l->l_cpuid), mode); 1049 } 1050 1051 void 1052 cputime(void *arg, VARENT *ve, int mode) 1053 { 1054 struct kinfo_proc2 *k; 1055 VAR *v; 1056 int32_t secs; 1057 int32_t psecs; /* "parts" of a second. first micro, then centi */ 1058 int fmtlen; 1059 1060 k = arg; 1061 v = ve->var; 1062 1063 /* 1064 * This counts time spent handling interrupts. We could 1065 * fix this, but it is not 100% trivial (and interrupt 1066 * time fractions only work on the sparc anyway). XXX 1067 */ 1068 secs = k->p_rtime_sec; 1069 psecs = k->p_rtime_usec; 1070 if (sumrusage) { 1071 secs += k->p_uctime_sec; 1072 psecs += k->p_uctime_usec; 1073 } 1074 /* 1075 * round and scale to 100's 1076 */ 1077 psecs = (psecs + 5000) / 10000; 1078 secs += psecs / 100; 1079 psecs = psecs % 100; 1080 1081 if (mode == WIDTHMODE) { 1082 /* 1083 * Ugg, this is the only field where a value of 0 is longer 1084 * than the column title. 1085 * Use SECSPERMIN, because secs is divided by that when 1086 * passed to iwidth(). 1087 */ 1088 if (secs == 0) 1089 secs = SECSPERMIN; 1090 1091 if (secs > v->longestp) { 1092 v->longestp = secs; 1093 /* "+6" for the ":%02ld.%02ld" in the printf() below */ 1094 fmtlen = iwidth(secs / SECSPERMIN) + 6; 1095 if (fmtlen > v->width) 1096 v->width = fmtlen; 1097 } 1098 } else { 1099 (void)printf("%*ld:%02ld.%02ld", v->width - 6, 1100 (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN), 1101 (long)psecs); 1102 } 1103 } 1104 1105 double 1106 getpcpu(k) 1107 const struct kinfo_proc2 *k; 1108 { 1109 static int failure; 1110 1111 if (!nlistread) 1112 failure = (kd) ? donlist() : 1; 1113 if (failure) 1114 return (0.0); 1115 1116 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 1117 1118 /* XXX - I don't like this */ 1119 if (k->p_swtime == 0 || (k->p_flag & L_INMEM) == 0 || 1120 k->p_realstat == SZOMB) 1121 return (0.0); 1122 if (rawcpu) 1123 return (100.0 * fxtofl(k->p_pctcpu)); 1124 return (100.0 * fxtofl(k->p_pctcpu) / 1125 (1.0 - exp(k->p_swtime * log(ccpu)))); 1126 } 1127 1128 void 1129 pcpu(void *arg, VARENT *ve, int mode) 1130 { 1131 struct kinfo_proc2 *k; 1132 VAR *v; 1133 1134 k = arg; 1135 v = ve->var; 1136 doubleprintorsetwidth(v, getpcpu(k), 1, mode); 1137 } 1138 1139 double 1140 getpmem(k) 1141 const struct kinfo_proc2 *k; 1142 { 1143 static int failure; 1144 double fracmem; 1145 int szptudot; 1146 1147 if (!nlistread) 1148 failure = (kd) ? donlist() : 1; 1149 if (failure) 1150 return (0.0); 1151 1152 if ((k->p_flag & L_INMEM) == 0) 1153 return (0.0); 1154 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 1155 szptudot = uspace/getpagesize(); 1156 /* XXX don't have info about shared */ 1157 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 1158 return (100.0 * fracmem); 1159 } 1160 1161 void 1162 pmem(void *arg, VARENT *ve, int mode) 1163 { 1164 struct kinfo_proc2 *k; 1165 VAR *v; 1166 1167 k = arg; 1168 v = ve->var; 1169 doubleprintorsetwidth(v, getpmem(k), 1, mode); 1170 } 1171 1172 void 1173 pagein(void *arg, VARENT *ve, int mode) 1174 { 1175 struct kinfo_proc2 *k; 1176 VAR *v; 1177 1178 k = arg; 1179 v = ve->var; 1180 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 1181 } 1182 1183 void 1184 maxrss(void *arg, VARENT *ve, int mode) 1185 { 1186 VAR *v; 1187 1188 v = ve->var; 1189 /* No need to check width! */ 1190 if (mode == PRINTMODE) 1191 (void)printf("%*s", v->width, "-"); 1192 } 1193 1194 void 1195 tsize(void *arg, VARENT *ve, int mode) 1196 { 1197 struct kinfo_proc2 *k; 1198 VAR *v; 1199 1200 k = arg; 1201 v = ve->var; 1202 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 1203 } 1204 1205 /* 1206 * Generic output routines. Print fields from various prototype 1207 * structures. 1208 */ 1209 static void 1210 printval(bp, v, mode) 1211 void *bp; 1212 VAR *v; 1213 int mode; 1214 { 1215 static char ofmt[32] = "%"; 1216 int width, vok, fmtlen; 1217 const char *fcp; 1218 char *cp; 1219 int64_t val; 1220 u_int64_t uval; 1221 1222 val = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1223 uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1224 1225 /* 1226 * Note that the "INF127" check is nonsensical for types 1227 * that are or can be signed. 1228 */ 1229 #define GET(type) (*(type *)bp) 1230 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 1231 1232 #define VSIGN 1 1233 #define VUNSIGN 2 1234 #define VPTR 3 1235 1236 if (mode == WIDTHMODE) { 1237 vok = 0; 1238 switch (v->type) { 1239 case CHAR: 1240 val = GET(char); 1241 vok = VSIGN; 1242 break; 1243 case UCHAR: 1244 uval = CHK_INF127(GET(u_char)); 1245 vok = VUNSIGN; 1246 break; 1247 case SHORT: 1248 val = GET(short); 1249 vok = VSIGN; 1250 break; 1251 case USHORT: 1252 uval = CHK_INF127(GET(u_short)); 1253 vok = VUNSIGN; 1254 break; 1255 case INT32: 1256 val = GET(int32_t); 1257 vok = VSIGN; 1258 break; 1259 case INT: 1260 val = GET(int); 1261 vok = VSIGN; 1262 break; 1263 case UINT: 1264 case UINT32: 1265 uval = CHK_INF127(GET(u_int)); 1266 vok = VUNSIGN; 1267 break; 1268 case LONG: 1269 val = GET(long); 1270 vok = VSIGN; 1271 break; 1272 case ULONG: 1273 uval = CHK_INF127(GET(u_long)); 1274 vok = VUNSIGN; 1275 break; 1276 case KPTR: 1277 uval = GET(u_int64_t); 1278 vok = VPTR; 1279 break; 1280 case KPTR24: 1281 uval = GET(u_int64_t); 1282 uval &= 0xffffff; 1283 vok = VPTR; 1284 break; 1285 case INT64: 1286 val = GET(int64_t); 1287 vok = VSIGN; 1288 break; 1289 case UINT64: 1290 uval = CHK_INF127(GET(u_int64_t)); 1291 vok = VUNSIGN; 1292 break; 1293 1294 case SIGLIST: 1295 default: 1296 /* nothing... */; 1297 } 1298 switch (vok) { 1299 case VSIGN: 1300 if (val < 0 && val < v->longestn) { 1301 v->longestn = val; 1302 fmtlen = iwidth(-val) + 1; 1303 if (fmtlen > v->width) 1304 v->width = fmtlen; 1305 } else if (val > 0 && val > v->longestp) { 1306 v->longestp = val; 1307 fmtlen = iwidth(val); 1308 if (fmtlen > v->width) 1309 v->width = fmtlen; 1310 } 1311 return; 1312 case VUNSIGN: 1313 if (uval > v->longestu) { 1314 v->longestu = uval; 1315 v->width = iwidth(uval); 1316 } 1317 return; 1318 case VPTR: 1319 fmtlen = 0; 1320 while (uval > 0) { 1321 uval >>= 4; 1322 fmtlen++; 1323 } 1324 if (fmtlen > v->width) 1325 v->width = fmtlen; 1326 return; 1327 } 1328 } 1329 1330 width = v->width; 1331 cp = ofmt + 1; 1332 fcp = v->fmt; 1333 if (v->flag & LJUST) 1334 *cp++ = '-'; 1335 *cp++ = '*'; 1336 while ((*cp++ = *fcp++) != '\0') 1337 continue; 1338 1339 switch (v->type) { 1340 case CHAR: 1341 (void)printf(ofmt, width, GET(char)); 1342 return; 1343 case UCHAR: 1344 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1345 return; 1346 case SHORT: 1347 (void)printf(ofmt, width, GET(short)); 1348 return; 1349 case USHORT: 1350 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1351 return; 1352 case INT: 1353 (void)printf(ofmt, width, GET(int)); 1354 return; 1355 case UINT: 1356 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1357 return; 1358 case LONG: 1359 (void)printf(ofmt, width, GET(long)); 1360 return; 1361 case ULONG: 1362 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1363 return; 1364 case KPTR: 1365 (void)printf(ofmt, width, GET(u_int64_t)); 1366 return; 1367 case KPTR24: 1368 (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff); 1369 return; 1370 case INT32: 1371 (void)printf(ofmt, width, GET(int32_t)); 1372 return; 1373 case UINT32: 1374 (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t))); 1375 return; 1376 case SIGLIST: 1377 { 1378 sigset_t *s = (sigset_t *)(void *)bp; 1379 size_t i; 1380 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1381 char buf[SIGSETSIZE * 8 + 1]; 1382 1383 for (i = 0; i < SIGSETSIZE; i++) 1384 (void)snprintf(&buf[i * 8], 9, "%.8x", 1385 s->__bits[(SIGSETSIZE - 1) - i]); 1386 1387 /* Skip leading zeroes */ 1388 for (i = 0; buf[i] == '0'; i++) 1389 continue; 1390 1391 if (buf[i] == '\0') 1392 i--; 1393 strprintorsetwidth(v, buf + i, mode); 1394 #undef SIGSETSIZE 1395 } 1396 return; 1397 case INT64: 1398 (void)printf(ofmt, width, GET(int64_t)); 1399 return; 1400 case UINT64: 1401 (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t))); 1402 return; 1403 default: 1404 errx(1, "unknown type %d", v->type); 1405 } 1406 #undef GET 1407 #undef CHK_INF127 1408 } 1409 1410 void 1411 pvar(void *arg, VARENT *ve, int mode) 1412 { 1413 VAR *v; 1414 1415 v = ve->var; 1416 if (v->flag & UAREA && !((struct kinfo_proc2 *)arg)->p_uvalid) { 1417 if (mode == PRINTMODE) 1418 (void)printf("%*s", v->width, "-"); 1419 return; 1420 } 1421 1422 (void)printval((char *)arg + v->off, v, mode); 1423 } 1424 1425 void 1426 putimeval(void *arg, VARENT *ve, int mode) 1427 { 1428 VAR *v = ve->var; 1429 struct kinfo_proc2 *k = arg; 1430 ulong secs = *(uint32_t *)((char *)arg + v->off); 1431 ulong usec = *(uint32_t *)((char *)arg + v->off + sizeof (uint32_t)); 1432 int fmtlen; 1433 1434 if (!k->p_uvalid) { 1435 if (mode == PRINTMODE) 1436 (void)printf("%*s", v->width, "-"); 1437 return; 1438 } 1439 1440 if (mode == WIDTHMODE) { 1441 if (secs == 0) 1442 /* non-zero so fmtlen is calculated at least once */ 1443 secs = 1; 1444 if (secs > v->longestu) { 1445 v->longestu = secs; 1446 if (secs <= 999) 1447 /* sss.ssssss */ 1448 fmtlen = iwidth(secs) + 6 + 1; 1449 else 1450 /* hh:mm:ss.ss */ 1451 fmtlen = iwidth((secs + 1) / SECSPERHOUR) 1452 + 2 + 1 + 2 + 1 + 2 + 1; 1453 if (fmtlen > v->width) 1454 v->width = fmtlen; 1455 } 1456 return; 1457 } 1458 1459 if (secs < 999) 1460 (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec); 1461 else { 1462 uint h, m; 1463 usec += 5000; 1464 if (usec >= 1000000) { 1465 usec -= 1000000; 1466 secs++; 1467 } 1468 m = secs / SECSPERMIN; 1469 secs -= m * SECSPERMIN; 1470 h = m / MINSPERHOUR; 1471 m -= h * MINSPERHOUR; 1472 (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs, 1473 usec / 10000u ); 1474 } 1475 } 1476 1477 void 1478 lname(void *arg, VARENT *ve, int mode) 1479 { 1480 struct kinfo_lwp *l; 1481 VAR *v; 1482 1483 l = arg; 1484 v = ve->var; 1485 if (l->l_name && l->l_name[0] != '\0') { 1486 strprintorsetwidth(v, l->l_name, mode); 1487 v->width = min(v->width, KI_LNAMELEN); 1488 } else { 1489 if (mode == PRINTMODE) 1490 (void)printf("%-*s", v->width, "-"); 1491 } 1492 } 1493