1 /* $NetBSD: print.c,v 1.117 2011/01/22 21:09:51 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.117 2011/01/22 21:09:51 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 105 #define min(a,b) ((a) <= (b) ? (a) : (b)) 106 107 static int 108 iwidth(u_int64_t v) 109 { 110 u_int64_t nlim, lim; 111 int w = 1; 112 113 for (lim = 10; v >= lim; lim = nlim) { 114 nlim = lim * 10; 115 w++; 116 if (nlim < lim) 117 break; 118 } 119 return w; 120 } 121 122 static char * 123 cmdpart(char *arg0) 124 { 125 char *cp; 126 127 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 128 } 129 130 void 131 printheader(void) 132 { 133 int len; 134 VAR *v; 135 struct varent *vent; 136 static int firsttime = 1; 137 static int noheader = 0; 138 139 /* 140 * If all the columns have user-specified null headers, 141 * don't print the blank header line at all. 142 */ 143 if (firsttime) { 144 SIMPLEQ_FOREACH(vent, &displaylist, next) { 145 if (vent->var->header[0]) 146 break; 147 } 148 if (vent == NULL) { 149 noheader = 1; 150 firsttime = 0; 151 } 152 153 } 154 if (noheader) 155 return; 156 157 SIMPLEQ_FOREACH(vent, &displaylist, next) { 158 v = vent->var; 159 if (firsttime) { 160 len = strlen(v->header); 161 if (len > v->width) 162 v->width = len; 163 totwidth += v->width + 1; /* +1 for space */ 164 } 165 if (v->flag & LJUST) { 166 if (SIMPLEQ_NEXT(vent, next) == NULL) /* last one */ 167 (void)printf("%s", v->header); 168 else 169 (void)printf("%-*s", v->width, 170 v->header); 171 } else 172 (void)printf("%*s", v->width, v->header); 173 if (SIMPLEQ_NEXT(vent, next) != NULL) 174 (void)putchar(' '); 175 } 176 (void)putchar('\n'); 177 if (firsttime) { 178 firsttime = 0; 179 totwidth--; /* take off last space */ 180 } 181 } 182 183 /* 184 * Return 1 if the command name in the argument vector (u-area) does 185 * not match the command name (p_comm) 186 */ 187 static int 188 titlecmp(char *name, char **argv) 189 { 190 char *title; 191 int namelen; 192 193 194 /* no argument vector == no match; system processes/threads do that */ 195 if (argv == 0 || argv[0] == 0) 196 return (1); 197 198 title = cmdpart(argv[0]); 199 200 /* the basename matches */ 201 if (!strcmp(name, title)) 202 return (0); 203 204 /* handle login shells, by skipping the leading - */ 205 if (title[0] == '-' && !strcmp(name, title + 1)) 206 return (0); 207 208 namelen = strlen(name); 209 210 /* handle daemons that report activity as daemonname: activity */ 211 if (argv[1] == 0 && 212 !strncmp(name, title, namelen) && 213 title[namelen + 0] == ':' && 214 title[namelen + 1] == ' ') 215 return (0); 216 217 return (1); 218 } 219 220 static void 221 doubleprintorsetwidth(VAR *v, double val, int prec, int mode) 222 { 223 int fmtlen; 224 225 if (mode == WIDTHMODE) { 226 if (val < 0.0 && val < v->longestnd) { 227 fmtlen = (int)log10(-val) + prec + 2; 228 v->longestnd = val; 229 if (fmtlen > v->width) 230 v->width = fmtlen; 231 } else if (val > 0.0 && val > v->longestpd) { 232 fmtlen = (int)log10(val) + prec + 1; 233 v->longestpd = val; 234 if (fmtlen > v->width) 235 v->width = fmtlen; 236 } 237 } else { 238 (void)printf("%*.*f", v->width, prec, val); 239 } 240 } 241 242 static void 243 intprintorsetwidth(VAR *v, int val, int mode) 244 { 245 int fmtlen; 246 247 if (mode == WIDTHMODE) { 248 if (val < 0 && val < v->longestn) { 249 v->longestn = val; 250 fmtlen = iwidth(-val) + 1; 251 if (fmtlen > v->width) 252 v->width = fmtlen; 253 } else if (val > 0 && val > v->longestp) { 254 v->longestp = val; 255 fmtlen = iwidth(val); 256 if (fmtlen > v->width) 257 v->width = fmtlen; 258 } 259 } else 260 (void)printf("%*d", v->width, val); 261 } 262 263 static void 264 strprintorsetwidth(VAR *v, const char *str, int mode) 265 { 266 int len; 267 268 if (mode == WIDTHMODE) { 269 len = strlen(str); 270 if (len > v->width) 271 v->width = len; 272 } else { 273 if (v->flag & LJUST) 274 (void)printf("%-*.*s", v->width, v->width, str); 275 else 276 (void)printf("%*.*s", v->width, v->width, str); 277 } 278 } 279 280 void 281 command(void *arg, VARENT *ve, int mode) 282 { 283 struct kinfo_proc2 *ki; 284 VAR *v; 285 int left; 286 char **argv, **p, *name; 287 288 if (mode == WIDTHMODE) 289 return; 290 291 ki = arg; 292 v = ve->var; 293 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 294 if (SIMPLEQ_NEXT(ve, next) == NULL) { 295 left = termwidth - (totwidth - v->width); 296 if (left < 1) /* already wrapped, just use std width */ 297 left = v->width; 298 } else 299 left = v->width; 300 } else 301 left = -1; 302 if (needenv && kd) { 303 argv = kvm_getenvv2(kd, ki, termwidth); 304 if ((p = argv) != NULL) { 305 while (*p) { 306 fmt_puts(*p, &left); 307 p++; 308 fmt_putc(' ', &left); 309 } 310 } 311 } 312 if (needcomm) { 313 name = ki->p_comm; 314 if (!commandonly) { 315 argv = kvm_getargv2(kd, ki, termwidth); 316 if ((p = argv) != NULL) { 317 while (*p) { 318 fmt_puts(*p, &left); 319 p++; 320 fmt_putc(' ', &left); 321 if (v->flag & ARGV0) 322 break; 323 } 324 if (!(v->flag & ARGV0) && 325 titlecmp(name, argv)) { 326 /* 327 * append the real command name within 328 * parentheses, if the command name 329 * does not match the one in the 330 * argument vector 331 */ 332 fmt_putc('(', &left); 333 fmt_puts(name, &left); 334 fmt_putc(')', &left); 335 } 336 } else { 337 /* 338 * Commands that don't set an argv vector 339 * are printed with square brackets if they 340 * are system commands. Otherwise they are 341 * printed within parentheses. 342 */ 343 if (ki->p_flag & P_SYSTEM) { 344 fmt_putc('[', &left); 345 fmt_puts(name, &left); 346 fmt_putc(']', &left); 347 } else { 348 fmt_putc('(', &left); 349 fmt_puts(name, &left); 350 fmt_putc(')', &left); 351 } 352 } 353 } else { 354 fmt_puts(name, &left); 355 } 356 } 357 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 358 (void)printf("%*s", left, ""); 359 } 360 361 void 362 groups(void *arg, VARENT *ve, int mode) 363 { 364 struct kinfo_proc2 *ki; 365 VAR *v; 366 int left, i; 367 char buf[16], *p; 368 369 if (mode == WIDTHMODE) 370 return; 371 372 ki = arg; 373 v = ve->var; 374 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 375 if (SIMPLEQ_NEXT(ve, next) == NULL) { 376 left = termwidth - (totwidth - v->width); 377 if (left < 1) /* already wrapped, just use std width */ 378 left = v->width; 379 } else 380 left = v->width; 381 } else 382 left = -1; 383 384 if (ki->p_ngroups == 0) 385 fmt_putc('-', &left); 386 387 for (i = 0; i < ki->p_ngroups; i++) { 388 (void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]); 389 if (i) 390 fmt_putc(' ', &left); 391 for (p = &buf[0]; *p; p++) 392 fmt_putc(*p, &left); 393 } 394 395 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 396 (void)printf("%*s", left, ""); 397 } 398 399 void 400 groupnames(void *arg, VARENT *ve, int mode) 401 { 402 struct kinfo_proc2 *ki; 403 VAR *v; 404 int left, i; 405 const char *p; 406 407 if (mode == WIDTHMODE) 408 return; 409 410 ki = arg; 411 v = ve->var; 412 if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) { 413 if (SIMPLEQ_NEXT(ve, next) == NULL) { 414 left = termwidth - (totwidth - v->width); 415 if (left < 1) /* already wrapped, just use std width */ 416 left = v->width; 417 } else 418 left = v->width; 419 } else 420 left = -1; 421 422 if (ki->p_ngroups == 0) 423 fmt_putc('-', &left); 424 425 for (i = 0; i < ki->p_ngroups; i++) { 426 if (i) 427 fmt_putc(' ', &left); 428 for (p = group_from_gid(ki->p_groups[i], 0); *p; p++) 429 fmt_putc(*p, &left); 430 } 431 432 if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0) 433 (void)printf("%*s", left, ""); 434 } 435 436 void 437 ucomm(void *arg, VARENT *ve, int mode) 438 { 439 struct kinfo_proc2 *k; 440 VAR *v; 441 442 k = arg; 443 v = ve->var; 444 strprintorsetwidth(v, k->p_comm, mode); 445 } 446 447 void 448 emul(void *arg, VARENT *ve, int mode) 449 { 450 struct kinfo_proc2 *k; 451 VAR *v; 452 453 k = arg; 454 v = ve->var; 455 strprintorsetwidth(v, k->p_ename, mode); 456 } 457 458 void 459 logname(void *arg, VARENT *ve, int mode) 460 { 461 struct kinfo_proc2 *k; 462 VAR *v; 463 464 k = arg; 465 v = ve->var; 466 strprintorsetwidth(v, k->p_login, mode); 467 } 468 469 void 470 state(void *arg, VARENT *ve, int mode) 471 { 472 struct kinfo_proc2 *k; 473 int flag, is_zombie; 474 char *cp; 475 VAR *v; 476 char buf[16]; 477 478 k = arg; 479 is_zombie = 0; 480 v = ve->var; 481 flag = k->p_flag; 482 cp = buf; 483 484 /* 485 * NOTE: There are historical letters, which are no longer used: 486 * 487 * - W: indicated that process is swapped out. 488 * - L: indicated non-zero l_holdcnt (i.e. that process was 489 * prevented from swapping-out. 490 * 491 * These letters should not be used for new states to avoid 492 * conflicts with old applications which might depend on them. 493 */ 494 switch (k->p_stat) { 495 496 case LSSTOP: 497 *cp = 'T'; 498 break; 499 500 case LSSLEEP: 501 if (flag & L_SINTR) /* interruptable (long) */ 502 *cp = (int)k->p_slptime >= maxslp ? 'I' : 'S'; 503 else 504 *cp = 'D'; 505 break; 506 507 case LSRUN: 508 case LSIDL: 509 *cp = 'R'; 510 break; 511 512 case LSONPROC: 513 *cp = 'O'; 514 break; 515 516 case LSZOMB: 517 *cp = 'Z'; 518 is_zombie = 1; 519 break; 520 521 case LSSUSPENDED: 522 *cp = 'U'; 523 break; 524 525 default: 526 *cp = '?'; 527 } 528 cp++; 529 if (k->p_nice < NZERO) 530 *cp++ = '<'; 531 else if (k->p_nice > NZERO) 532 *cp++ = 'N'; 533 if (flag & P_TRACED) 534 *cp++ = 'X'; 535 if (flag & P_WEXIT && !is_zombie) 536 *cp++ = 'E'; 537 if (flag & P_PPWAIT) 538 *cp++ = 'V'; 539 if (flag & P_SYSTEM) 540 *cp++ = 'K'; 541 if (k->p_eflag & EPROC_SLEADER) 542 *cp++ = 's'; 543 if (flag & P_SA) 544 *cp++ = 'a'; 545 else if (k->p_nlwps > 1) 546 *cp++ = 'l'; 547 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid) 548 *cp++ = '+'; 549 *cp = '\0'; 550 strprintorsetwidth(v, buf, mode); 551 } 552 553 void 554 lstate(void *arg, VARENT *ve, int mode) 555 { 556 struct kinfo_lwp *k; 557 int flag, is_zombie; 558 char *cp; 559 VAR *v; 560 char buf[16]; 561 562 k = arg; 563 is_zombie = 0; 564 v = ve->var; 565 flag = k->l_flag; 566 cp = buf; 567 568 switch (k->l_stat) { 569 570 case LSSTOP: 571 *cp = 'T'; 572 break; 573 574 case LSSLEEP: 575 if (flag & L_SINTR) /* interruptible (long) */ 576 *cp = (int)k->l_slptime >= maxslp ? 'I' : 'S'; 577 else 578 *cp = 'D'; 579 break; 580 581 case LSRUN: 582 case LSIDL: 583 *cp = 'R'; 584 break; 585 586 case LSONPROC: 587 *cp = 'O'; 588 break; 589 590 case LSZOMB: 591 case LSDEAD: 592 *cp = 'Z'; 593 is_zombie = 1; 594 break; 595 596 case LSSUSPENDED: 597 *cp = 'U'; 598 break; 599 600 default: 601 *cp = '?'; 602 } 603 cp++; 604 if (flag & L_SYSTEM) 605 *cp++ = 'K'; 606 if (flag & L_SA) 607 *cp++ = 'a'; 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, pgtok(k->p_vm_msize), mode); 981 } 982 983 void 984 rssize(void *arg, VARENT *ve, int mode) 985 { 986 struct kinfo_proc2 *k; 987 VAR *v; 988 989 k = arg; 990 v = ve->var; 991 /* XXX don't have info about shared */ 992 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 993 } 994 995 void 996 p_rssize(void *arg, VARENT *ve, int mode) /* doesn't account for text */ 997 { 998 struct kinfo_proc2 *k; 999 VAR *v; 1000 1001 k = arg; 1002 v = ve->var; 1003 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 1004 } 1005 1006 void 1007 cpuid(void *arg, VARENT *ve, int mode) 1008 { 1009 struct kinfo_lwp *l; 1010 VAR *v; 1011 1012 l = arg; 1013 v = ve->var; 1014 intprintorsetwidth(v, l->l_cpuid, mode); 1015 } 1016 1017 void 1018 cputime(void *arg, VARENT *ve, int mode) 1019 { 1020 struct kinfo_proc2 *k; 1021 VAR *v; 1022 int32_t secs; 1023 int32_t psecs; /* "parts" of a second. first micro, then centi */ 1024 int fmtlen; 1025 1026 k = arg; 1027 v = ve->var; 1028 1029 /* 1030 * This counts time spent handling interrupts. We could 1031 * fix this, but it is not 100% trivial (and interrupt 1032 * time fractions only work on the sparc anyway). XXX 1033 */ 1034 secs = k->p_rtime_sec; 1035 psecs = k->p_rtime_usec; 1036 if (sumrusage) { 1037 secs += k->p_uctime_sec; 1038 psecs += k->p_uctime_usec; 1039 } 1040 /* 1041 * round and scale to 100's 1042 */ 1043 psecs = (psecs + 5000) / 10000; 1044 secs += psecs / 100; 1045 psecs = psecs % 100; 1046 1047 if (mode == WIDTHMODE) { 1048 /* 1049 * Ugg, this is the only field where a value of 0 is longer 1050 * than the column title. 1051 * Use SECSPERMIN, because secs is divided by that when 1052 * passed to iwidth(). 1053 */ 1054 if (secs == 0) 1055 secs = SECSPERMIN; 1056 1057 if (secs > v->longestp) { 1058 v->longestp = secs; 1059 /* "+6" for the ":%02ld.%02ld" in the printf() below */ 1060 fmtlen = iwidth(secs / SECSPERMIN) + 6; 1061 if (fmtlen > v->width) 1062 v->width = fmtlen; 1063 } 1064 } else { 1065 (void)printf("%*ld:%02ld.%02ld", v->width - 6, 1066 (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN), 1067 (long)psecs); 1068 } 1069 } 1070 1071 double 1072 getpcpu(k) 1073 const struct kinfo_proc2 *k; 1074 { 1075 static int failure; 1076 1077 if (!nlistread) 1078 failure = (kd) ? donlist() : 1; 1079 if (failure) 1080 return (0.0); 1081 1082 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 1083 1084 if (k->p_swtime == 0 || k->p_realstat == SZOMB) 1085 return (0.0); 1086 if (rawcpu) 1087 return (100.0 * fxtofl(k->p_pctcpu)); 1088 return (100.0 * fxtofl(k->p_pctcpu) / 1089 (1.0 - exp(k->p_swtime * log(ccpu)))); 1090 } 1091 1092 void 1093 pcpu(void *arg, VARENT *ve, int mode) 1094 { 1095 struct kinfo_proc2 *k; 1096 VAR *v; 1097 double dbl; 1098 1099 k = arg; 1100 v = ve->var; 1101 dbl = getpcpu(k); 1102 doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode); 1103 } 1104 1105 double 1106 getpmem(k) 1107 const struct kinfo_proc2 *k; 1108 { 1109 static int failure; 1110 double fracmem; 1111 int szptudot; 1112 1113 if (!nlistread) 1114 failure = (kd) ? donlist() : 1; 1115 if (failure) 1116 return (0.0); 1117 1118 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 1119 szptudot = uspace/getpagesize(); 1120 /* XXX don't have info about shared */ 1121 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 1122 return (100.0 * fracmem); 1123 } 1124 1125 void 1126 pmem(void *arg, VARENT *ve, int mode) 1127 { 1128 struct kinfo_proc2 *k; 1129 VAR *v; 1130 1131 k = arg; 1132 v = ve->var; 1133 doubleprintorsetwidth(v, getpmem(k), 1, mode); 1134 } 1135 1136 void 1137 pagein(void *arg, VARENT *ve, int mode) 1138 { 1139 struct kinfo_proc2 *k; 1140 VAR *v; 1141 1142 k = arg; 1143 v = ve->var; 1144 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 1145 } 1146 1147 void 1148 maxrss(void *arg, VARENT *ve, int mode) 1149 { 1150 VAR *v; 1151 1152 v = ve->var; 1153 /* No need to check width! */ 1154 if (mode == PRINTMODE) 1155 (void)printf("%*s", v->width, "-"); 1156 } 1157 1158 void 1159 tsize(void *arg, VARENT *ve, int mode) 1160 { 1161 struct kinfo_proc2 *k; 1162 VAR *v; 1163 1164 k = arg; 1165 v = ve->var; 1166 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 1167 } 1168 1169 /* 1170 * Generic output routines. Print fields from various prototype 1171 * structures. 1172 */ 1173 static void 1174 printval(bp, v, mode) 1175 void *bp; 1176 VAR *v; 1177 int mode; 1178 { 1179 static char ofmt[32] = "%"; 1180 int width, vok, fmtlen; 1181 const char *fcp; 1182 char *cp; 1183 int64_t val; 1184 u_int64_t uval; 1185 1186 val = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1187 uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 1188 1189 /* 1190 * Note that the "INF127" check is nonsensical for types 1191 * that are or can be signed. 1192 */ 1193 #define GET(type) (*(type *)bp) 1194 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 1195 1196 #define VSIGN 1 1197 #define VUNSIGN 2 1198 #define VPTR 3 1199 1200 if (mode == WIDTHMODE) { 1201 vok = 0; 1202 switch (v->type) { 1203 case CHAR: 1204 val = GET(char); 1205 vok = VSIGN; 1206 break; 1207 case UCHAR: 1208 uval = CHK_INF127(GET(u_char)); 1209 vok = VUNSIGN; 1210 break; 1211 case SHORT: 1212 val = GET(short); 1213 vok = VSIGN; 1214 break; 1215 case USHORT: 1216 uval = CHK_INF127(GET(u_short)); 1217 vok = VUNSIGN; 1218 break; 1219 case INT32: 1220 val = GET(int32_t); 1221 vok = VSIGN; 1222 break; 1223 case INT: 1224 val = GET(int); 1225 vok = VSIGN; 1226 break; 1227 case UINT: 1228 case UINT32: 1229 uval = CHK_INF127(GET(u_int)); 1230 vok = VUNSIGN; 1231 break; 1232 case LONG: 1233 val = GET(long); 1234 vok = VSIGN; 1235 break; 1236 case ULONG: 1237 uval = CHK_INF127(GET(u_long)); 1238 vok = VUNSIGN; 1239 break; 1240 case KPTR: 1241 uval = GET(u_int64_t); 1242 vok = VPTR; 1243 break; 1244 case KPTR24: 1245 uval = GET(u_int64_t); 1246 uval &= 0xffffff; 1247 vok = VPTR; 1248 break; 1249 case INT64: 1250 val = GET(int64_t); 1251 vok = VSIGN; 1252 break; 1253 case UINT64: 1254 uval = CHK_INF127(GET(u_int64_t)); 1255 vok = VUNSIGN; 1256 break; 1257 1258 case SIGLIST: 1259 default: 1260 /* nothing... */; 1261 } 1262 switch (vok) { 1263 case VSIGN: 1264 if (val < 0 && val < v->longestn) { 1265 v->longestn = val; 1266 fmtlen = iwidth(-val) + 1; 1267 if (fmtlen > v->width) 1268 v->width = fmtlen; 1269 } else if (val > 0 && val > v->longestp) { 1270 v->longestp = val; 1271 fmtlen = iwidth(val); 1272 if (fmtlen > v->width) 1273 v->width = fmtlen; 1274 } 1275 return; 1276 case VUNSIGN: 1277 if (uval > v->longestu) { 1278 v->longestu = uval; 1279 v->width = iwidth(uval); 1280 } 1281 return; 1282 case VPTR: 1283 fmtlen = 0; 1284 while (uval > 0) { 1285 uval >>= 4; 1286 fmtlen++; 1287 } 1288 if (fmtlen > v->width) 1289 v->width = fmtlen; 1290 return; 1291 } 1292 } 1293 1294 width = v->width; 1295 cp = ofmt + 1; 1296 fcp = v->fmt; 1297 if (v->flag & LJUST) 1298 *cp++ = '-'; 1299 *cp++ = '*'; 1300 while ((*cp++ = *fcp++) != '\0') 1301 continue; 1302 1303 switch (v->type) { 1304 case CHAR: 1305 (void)printf(ofmt, width, GET(char)); 1306 return; 1307 case UCHAR: 1308 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1309 return; 1310 case SHORT: 1311 (void)printf(ofmt, width, GET(short)); 1312 return; 1313 case USHORT: 1314 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1315 return; 1316 case INT: 1317 (void)printf(ofmt, width, GET(int)); 1318 return; 1319 case UINT: 1320 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1321 return; 1322 case LONG: 1323 (void)printf(ofmt, width, GET(long)); 1324 return; 1325 case ULONG: 1326 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1327 return; 1328 case KPTR: 1329 (void)printf(ofmt, width, GET(u_int64_t)); 1330 return; 1331 case KPTR24: 1332 (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff); 1333 return; 1334 case INT32: 1335 (void)printf(ofmt, width, GET(int32_t)); 1336 return; 1337 case UINT32: 1338 (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t))); 1339 return; 1340 case SIGLIST: 1341 { 1342 sigset_t *s = (sigset_t *)(void *)bp; 1343 size_t i; 1344 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1345 char buf[SIGSETSIZE * 8 + 1]; 1346 1347 for (i = 0; i < SIGSETSIZE; i++) 1348 (void)snprintf(&buf[i * 8], 9, "%.8x", 1349 s->__bits[(SIGSETSIZE - 1) - i]); 1350 1351 /* Skip leading zeroes */ 1352 for (i = 0; buf[i] == '0'; i++) 1353 continue; 1354 1355 if (buf[i] == '\0') 1356 i--; 1357 strprintorsetwidth(v, buf + i, mode); 1358 #undef SIGSETSIZE 1359 } 1360 return; 1361 case INT64: 1362 (void)printf(ofmt, width, GET(int64_t)); 1363 return; 1364 case UINT64: 1365 (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t))); 1366 return; 1367 default: 1368 errx(1, "unknown type %d", v->type); 1369 } 1370 #undef GET 1371 #undef CHK_INF127 1372 } 1373 1374 void 1375 pvar(void *arg, VARENT *ve, int mode) 1376 { 1377 VAR *v; 1378 1379 v = ve->var; 1380 if (v->flag & UAREA && !((struct kinfo_proc2 *)arg)->p_uvalid) { 1381 if (mode == PRINTMODE) 1382 (void)printf("%*s", v->width, "-"); 1383 return; 1384 } 1385 1386 (void)printval((char *)arg + v->off, v, mode); 1387 } 1388 1389 void 1390 putimeval(void *arg, VARENT *ve, int mode) 1391 { 1392 VAR *v = ve->var; 1393 struct kinfo_proc2 *k = arg; 1394 ulong secs = *(uint32_t *)((char *)arg + v->off); 1395 ulong usec = *(uint32_t *)((char *)arg + v->off + sizeof (uint32_t)); 1396 int fmtlen; 1397 1398 if (!k->p_uvalid) { 1399 if (mode == PRINTMODE) 1400 (void)printf("%*s", v->width, "-"); 1401 return; 1402 } 1403 1404 if (mode == WIDTHMODE) { 1405 if (secs == 0) 1406 /* non-zero so fmtlen is calculated at least once */ 1407 secs = 1; 1408 if (secs > v->longestu) { 1409 v->longestu = secs; 1410 if (secs <= 999) 1411 /* sss.ssssss */ 1412 fmtlen = iwidth(secs) + 6 + 1; 1413 else 1414 /* hh:mm:ss.ss */ 1415 fmtlen = iwidth((secs + 1) / SECSPERHOUR) 1416 + 2 + 1 + 2 + 1 + 2 + 1; 1417 if (fmtlen > v->width) 1418 v->width = fmtlen; 1419 } 1420 return; 1421 } 1422 1423 if (secs < 999) 1424 (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec); 1425 else { 1426 uint h, m; 1427 usec += 5000; 1428 if (usec >= 1000000) { 1429 usec -= 1000000; 1430 secs++; 1431 } 1432 m = secs / SECSPERMIN; 1433 secs -= m * SECSPERMIN; 1434 h = m / MINSPERHOUR; 1435 m -= h * MINSPERHOUR; 1436 (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs, 1437 usec / 10000u ); 1438 } 1439 } 1440 1441 void 1442 lname(void *arg, VARENT *ve, int mode) 1443 { 1444 struct kinfo_lwp *l; 1445 VAR *v; 1446 1447 l = arg; 1448 v = ve->var; 1449 if (l->l_name && l->l_name[0] != '\0') { 1450 strprintorsetwidth(v, l->l_name, mode); 1451 v->width = min(v->width, KI_LNAMELEN); 1452 } else { 1453 if (mode == PRINTMODE) 1454 (void)printf("%-*s", v->width, "-"); 1455 } 1456 } 1457