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