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