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