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