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