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