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