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