1 /* $NetBSD: print.c,v 1.57 2000/10/23 05:54:06 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Simon Burge. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1990, 1993, 1994 41 * The Regents of the University of California. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 */ 71 72 #include <sys/cdefs.h> 73 #ifndef lint 74 #if 0 75 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; 76 #else 77 __RCSID("$NetBSD: print.c,v 1.57 2000/10/23 05:54:06 simonb Exp $"); 78 #endif 79 #endif /* not lint */ 80 81 #include <sys/param.h> 82 #include <sys/time.h> 83 #include <sys/resource.h> 84 #include <sys/proc.h> 85 #include <sys/stat.h> 86 #include <sys/ucred.h> 87 #include <sys/sysctl.h> 88 89 #include <err.h> 90 #include <kvm.h> 91 #include <math.h> 92 #include <nlist.h> 93 #include <pwd.h> 94 #include <stddef.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <string.h> 98 #include <time.h> 99 #include <tzfile.h> 100 #include <unistd.h> 101 102 #include "ps.h" 103 104 static char *cmdpart __P((char *)); 105 static void printval __P((void *, VAR *, int)); 106 static int titlecmp __P((char *, char **)); 107 108 static void doubleprintorsetwidth __P((VAR *, double, int, int)); 109 static void intprintorsetwidth __P((VAR *, int, int)); 110 static void strprintorsetwidth __P((VAR *, const char *, int)); 111 112 #define min(a,b) ((a) <= (b) ? (a) : (b)) 113 #define max(a,b) ((a) >= (b) ? (a) : (b)) 114 115 static char * 116 cmdpart(arg0) 117 char *arg0; 118 { 119 char *cp; 120 121 return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); 122 } 123 124 void 125 printheader() 126 { 127 int len; 128 VAR *v; 129 struct varent *vent; 130 static int firsttime = 1; 131 132 for (vent = vhead; vent; vent = vent->next) { 133 v = vent->var; 134 if (firsttime) { 135 len = strlen(v->header); 136 if (len > v->width) 137 v->width = len; 138 totwidth += v->width + 1; /* +1 for space */ 139 } 140 if (v->flag & LJUST) { 141 if (vent->next == NULL) /* last one */ 142 (void)printf("%s", v->header); 143 else 144 (void)printf("%-*s", v->width, 145 v->header); 146 } else 147 (void)printf("%*s", v->width, v->header); 148 if (vent->next != NULL) 149 (void)putchar(' '); 150 } 151 (void)putchar('\n'); 152 if (firsttime) { 153 firsttime = 0; 154 totwidth--; /* take off last space */ 155 } 156 } 157 158 static int 159 titlecmp(name, argv) 160 char *name; 161 char **argv; 162 { 163 char *title; 164 int namelen; 165 166 if (argv == 0 || argv[0] == 0) 167 return (1); 168 169 title = cmdpart(argv[0]); 170 171 if (!strcmp(name, title)) 172 return (0); 173 174 if (title[0] == '-' && !strcmp(name, title+1)) 175 return (0); 176 177 namelen = strlen(name); 178 179 if (argv[1] == 0 && 180 !strncmp(name, title, namelen) && 181 title[namelen + 0] == ':' && 182 title[namelen + 1] == ' ') 183 return (0); 184 185 return (1); 186 } 187 188 static void 189 doubleprintorsetwidth(v, val, prec, mode) 190 VAR *v; 191 double val; 192 int prec; 193 int mode; 194 { 195 int fmtlen; 196 197 if (mode == WIDTHMODE) { 198 if (val < 0.0 && val < v->longestnd) { 199 fmtlen = (int)log10(-val) + prec + 2; 200 v->longestnd = val; 201 if (fmtlen > v->width) 202 v->width = fmtlen; 203 } else if (val > 0.0 && val > v->longestpd) { 204 fmtlen = (int)log10(val) + prec + 1; 205 v->longestpd = val; 206 if (fmtlen > v->width) 207 v->width = fmtlen; 208 } 209 } else { 210 printf("%*.*f", v->width, prec, val); 211 } 212 } 213 214 static void 215 intprintorsetwidth(v, val, mode) 216 VAR *v; 217 int val; 218 int mode; 219 { 220 int fmtlen; 221 222 if (mode == WIDTHMODE) { 223 if (val < 0 && val < v->longestn) { 224 fmtlen = (int)log10((double)-val) + 2; 225 v->longestn = val; 226 if (fmtlen > v->width) 227 v->width = fmtlen; 228 } else if (val > 0 && val > v->longestp) { 229 fmtlen = (int)log10((double)val) + 1; 230 v->longestp = val; 231 if (fmtlen > v->width) 232 v->width = fmtlen; 233 } 234 } else 235 printf("%*d", v->width, val); 236 } 237 238 static void 239 strprintorsetwidth(v, str, mode) 240 VAR *v; 241 const char *str; 242 { 243 int len; 244 245 if (mode == WIDTHMODE) { 246 len = strlen(str); 247 if (len > v->width) 248 v->width = len; 249 } else { 250 if (v->flag & LJUST) 251 printf("%-*.*s", v->width, v->width, str); 252 else 253 printf("%*.*s", v->width, v->width, str); 254 } 255 } 256 257 void 258 command(ki, ve, mode) 259 struct kinfo_proc2 *ki; 260 VARENT *ve; 261 int mode; 262 { 263 VAR *v; 264 int left; 265 char **argv, **p, *name; 266 267 if (mode == WIDTHMODE) 268 return; 269 270 v = ve->var; 271 if (ve->next != NULL || termwidth != UNLIMITED) { 272 if (ve->next == NULL) { 273 left = termwidth - (totwidth - v->width); 274 if (left < 1) /* already wrapped, just use std width */ 275 left = v->width; 276 } else 277 left = v->width; 278 } else 279 left = -1; 280 if (needenv && kd) { 281 argv = kvm_getenvv2(kd, ki, termwidth); 282 if ((p = argv) != NULL) { 283 while (*p) { 284 fmt_puts(*p, &left); 285 p++; 286 fmt_putc(' ', &left); 287 } 288 } 289 } 290 if (needcomm) { 291 name = ki->p_comm; 292 if (!commandonly) { 293 argv = NULL; 294 if (!use_procfs) 295 argv = kvm_getargv2(kd, ki, termwidth); 296 else 297 argv = procfs_getargv(ki, termwidth); 298 if ((p = argv) != NULL) { 299 while (*p) { 300 fmt_puts(*p, &left); 301 p++; 302 fmt_putc(' ', &left); 303 } 304 } 305 if (titlecmp(name, argv)) { 306 fmt_putc('(', &left); 307 fmt_puts(name, &left); 308 fmt_putc(')', &left); 309 } 310 if (use_procfs && argv) { 311 free(argv[0]); 312 free(argv); 313 } 314 } else { 315 fmt_puts(name, &left); 316 } 317 } 318 if (ve->next && left > 0) 319 printf("%*s", left, ""); 320 } 321 322 void 323 ucomm(k, ve, mode) 324 struct kinfo_proc2 *k; 325 VARENT *ve; 326 int mode; 327 { 328 VAR *v; 329 330 v = ve->var; 331 strprintorsetwidth(v, k->p_comm, mode); 332 } 333 334 void 335 logname(k, ve, mode) 336 struct kinfo_proc2 *k; 337 VARENT *ve; 338 int mode; 339 { 340 VAR *v; 341 342 v = ve->var; 343 strprintorsetwidth(v, k->p_login, mode); 344 } 345 346 void 347 state(k, ve, mode) 348 struct kinfo_proc2 *k; 349 VARENT *ve; 350 int mode; 351 { 352 int flag, is_zombie; 353 char *cp; 354 VAR *v; 355 char buf[16]; 356 357 is_zombie = 0; 358 v = ve->var; 359 flag = k->p_flag; 360 cp = buf; 361 362 switch (k->p_stat) { 363 364 case SSTOP: 365 *cp = 'T'; 366 break; 367 368 case SSLEEP: 369 if (flag & P_SINTR) /* interuptable (long) */ 370 *cp = k->p_slptime >= MAXSLP ? 'I' : 'S'; 371 else 372 *cp = 'D'; 373 break; 374 375 case SRUN: 376 case SIDL: 377 case SONPROC: 378 *cp = 'R'; 379 break; 380 381 case SZOMB: 382 case SDEAD: 383 *cp = 'Z'; 384 is_zombie = 1; 385 break; 386 387 default: 388 *cp = '?'; 389 } 390 cp++; 391 if (flag & P_INMEM) { 392 } else 393 *cp++ = 'W'; 394 if (k->p_nice < NZERO) 395 *cp++ = '<'; 396 else if (k->p_nice > NZERO) 397 *cp++ = 'N'; 398 if (flag & P_TRACED) 399 *cp++ = 'X'; 400 if (flag & P_WEXIT && !is_zombie) 401 *cp++ = 'E'; 402 if (flag & P_PPWAIT) 403 *cp++ = 'V'; 404 if (flag & P_SYSTEM) 405 *cp++ = 'K'; 406 /* system process might have this too, don't need to double up */ 407 else if (k->p_holdcnt) 408 *cp++ = 'L'; 409 if (k->p_eflag & EPROC_SLEADER) 410 *cp++ = 's'; 411 if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid) 412 *cp++ = '+'; 413 *cp = '\0'; 414 strprintorsetwidth(v, buf, mode); 415 } 416 417 void 418 pnice(k, ve, mode) 419 struct kinfo_proc2 *k; 420 VARENT *ve; 421 int mode; 422 { 423 VAR *v; 424 425 v = ve->var; 426 intprintorsetwidth(v, k->p_nice - NZERO, mode); 427 } 428 429 void 430 pri(k, ve, mode) 431 struct kinfo_proc2 *k; 432 VARENT *ve; 433 int mode; 434 { 435 VAR *v; 436 437 v = ve->var; 438 intprintorsetwidth(v, k->p_priority - PZERO, mode); 439 } 440 441 void 442 uname(k, ve, mode) 443 struct kinfo_proc2 *k; 444 VARENT *ve; 445 int mode; 446 { 447 VAR *v; 448 449 v = ve->var; 450 strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode); 451 } 452 453 void 454 runame(k, ve, mode) 455 struct kinfo_proc2 *k; 456 VARENT *ve; 457 int mode; 458 { 459 VAR *v; 460 461 v = ve->var; 462 strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode); 463 } 464 465 void 466 tdev(k, ve, mode) 467 struct kinfo_proc2 *k; 468 VARENT *ve; 469 int mode; 470 { 471 VAR *v; 472 dev_t dev; 473 char buff[16]; 474 475 v = ve->var; 476 dev = k->p_tdev; 477 if (dev == NODEV) { 478 /* 479 * Minimum width is width of header - we don't 480 * need to check it every time. 481 */ 482 if (mode == PRINTMODE) 483 (void)printf("%*s", v->width, "??"); 484 } else { 485 (void)snprintf(buff, sizeof(buff), 486 "%d/%d", major(dev), minor(dev)); 487 strprintorsetwidth(v, buff, mode); 488 } 489 } 490 491 void 492 tname(k, ve, mode) 493 struct kinfo_proc2 *k; 494 VARENT *ve; 495 int mode; 496 { 497 VAR *v; 498 dev_t dev; 499 const char *ttname; 500 int noctty; 501 502 v = ve->var; 503 dev = k->p_tdev; 504 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 505 /* 506 * Minimum width is width of header - we don't 507 * need to check it every time. 508 */ 509 if (mode == PRINTMODE) 510 (void)printf("%-*s", v->width, "??"); 511 } else { 512 if (strncmp(ttname, "tty", 3) == 0 || 513 strncmp(ttname, "dty", 3) == 0) 514 ttname += 3; 515 noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0; 516 if (mode == WIDTHMODE) { 517 int fmtlen; 518 519 fmtlen = strlen(ttname) + noctty; 520 if (v->width < fmtlen) 521 v->width = fmtlen; 522 } else { 523 if (noctty) 524 printf("%-*s-", v->width - 1, ttname); 525 else 526 printf("%-*s", v->width, ttname); 527 } 528 } 529 } 530 531 void 532 longtname(k, ve, mode) 533 struct kinfo_proc2 *k; 534 VARENT *ve; 535 int mode; 536 { 537 VAR *v; 538 dev_t dev; 539 const char *ttname; 540 541 v = ve->var; 542 dev = k->p_tdev; 543 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) { 544 /* 545 * Minimum width is width of header - we don't 546 * need to check it every time. 547 */ 548 if (mode == PRINTMODE) 549 (void)printf("%-*s", v->width, "??"); 550 } 551 else { 552 strprintorsetwidth(v, ttname, mode); 553 } 554 } 555 556 void 557 started(k, ve, mode) 558 struct kinfo_proc2 *k; 559 VARENT *ve; 560 int mode; 561 { 562 VAR *v; 563 static time_t now; 564 time_t startt; 565 struct tm *tp; 566 char buf[100], *cp; 567 568 /* 569 * XXX: The maximum width of this field is the same as the header 570 * "STARTED" for locales that have 3 letter abbreviated month 571 * names and 2 letter am/pm descriptions. 572 */ 573 if (mode == WIDTHMODE) 574 return; 575 576 v = ve->var; 577 if (!k->p_uvalid) { 578 if (mode == PRINTMODE) 579 (void)printf("%*s", v->width, "-"); 580 return; 581 } 582 583 startt = k->p_ustart_sec; 584 tp = localtime(&startt); 585 if (!now) 586 (void)time(&now); 587 if (now - k->p_ustart_sec < SECSPERDAY) 588 /* I *hate* SCCS... */ 589 (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp); 590 else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY) 591 /* I *hate* SCCS... */ 592 (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp); 593 else 594 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); 595 /* %e and %l can start with a space. */ 596 cp = buf; 597 if (*cp == ' ') 598 cp++; 599 strprintorsetwidth(v, cp, mode); 600 } 601 602 void 603 lstarted(k, ve, mode) 604 struct kinfo_proc2 *k; 605 VARENT *ve; 606 int mode; 607 { 608 VAR *v; 609 time_t startt; 610 char buf[100]; 611 612 v = ve->var; 613 if (!k->p_uvalid) { 614 /* 615 * Minimum width is less than header - we don't 616 * need to check it every time. 617 */ 618 if (mode == PRINTMODE) 619 (void)printf("%*s", v->width, "-"); 620 return; 621 } 622 startt = k->p_ustart_sec; 623 624 /* assume all times are the same length */ 625 if (mode != WIDTHMODE || v->width == 0) { 626 (void)strftime(buf, sizeof(buf) -1, "%c", 627 localtime(&startt)); 628 strprintorsetwidth(v, buf, mode); 629 } 630 } 631 632 void 633 wchan(k, ve, mode) 634 struct kinfo_proc2 *k; 635 VARENT *ve; 636 int mode; 637 { 638 VAR *v; 639 char *buf; 640 641 v = ve->var; 642 if (k->p_wchan) { 643 if (k->p_wmesg) { 644 strprintorsetwidth(v, k->p_wmesg, mode); 645 v->width = min(v->width, WMESGLEN); 646 } else { 647 (void)asprintf(&buf, "%-*llx", v->width, 648 (long long)k->p_wchan); 649 if (buf == NULL) 650 err(1, "%s", ""); 651 strprintorsetwidth(v, buf, mode); 652 v->width = min(v->width, WMESGLEN); 653 free(buf); 654 } 655 } else { 656 if (mode == PRINTMODE) 657 (void)printf("%-*s", v->width, "-"); 658 } 659 } 660 661 #define pgtok(a) (((a)*getpagesize())/1024) 662 663 void 664 vsize(k, ve, mode) 665 struct kinfo_proc2 *k; 666 VARENT *ve; 667 int mode; 668 { 669 VAR *v; 670 671 v = ve->var; 672 intprintorsetwidth(v, 673 pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode); 674 } 675 676 void 677 rssize(k, ve, mode) 678 struct kinfo_proc2 *k; 679 VARENT *ve; 680 int mode; 681 { 682 VAR *v; 683 684 v = ve->var; 685 /* XXX don't have info about shared */ 686 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 687 } 688 689 void 690 p_rssize(k, ve, mode) /* doesn't account for text */ 691 struct kinfo_proc2 *k; 692 VARENT *ve; 693 int mode; 694 { 695 VAR *v; 696 697 v = ve->var; 698 intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode); 699 } 700 701 void 702 cputime(k, ve, mode) 703 struct kinfo_proc2 *k; 704 VARENT *ve; 705 int mode; 706 { 707 VAR *v; 708 long secs; 709 long psecs; /* "parts" of a second. first micro, then centi */ 710 int fmtlen; 711 712 v = ve->var; 713 if (P_ZOMBIE(k) || k->p_uvalid == 0) { 714 secs = 0; 715 psecs = 0; 716 } else { 717 /* 718 * This counts time spent handling interrupts. We could 719 * fix this, but it is not 100% trivial (and interrupt 720 * time fractions only work on the sparc anyway). XXX 721 */ 722 secs = k->p_rtime_sec; 723 psecs = k->p_rtime_usec; 724 if (sumrusage) { 725 secs += k->p_uctime_sec; 726 psecs += k->p_uctime_usec; 727 } 728 /* 729 * round and scale to 100's 730 */ 731 psecs = (psecs + 5000) / 10000; 732 secs += psecs / 100; 733 psecs = psecs % 100; 734 } 735 if (mode == WIDTHMODE) { 736 /* 737 * Ugg, this is the only field where a value of 0 longer 738 * than the column title, and log10(0) isn't good enough. 739 * Use SECSPERMIN, because secs is divided by that when 740 * passed to log10(). 741 */ 742 if (secs == 0 && v->longestp == 0) 743 secs = SECSPERMIN; 744 if (secs > v->longestp) { 745 /* "+6" for the "%02ld.%02ld" in the printf() below */ 746 fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6; 747 v->longestp = secs; 748 if (fmtlen > v->width) 749 v->width = fmtlen; 750 } 751 } else { 752 printf("%*ld:%02ld.%02ld", v->width - 6, secs / SECSPERMIN, 753 secs % SECSPERMIN, psecs); 754 } 755 } 756 757 double 758 getpcpu(k) 759 struct kinfo_proc2 *k; 760 { 761 static int failure; 762 763 if (!nlistread) 764 failure = (kd) ? donlist() : 1; 765 if (failure) 766 return (0.0); 767 768 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 769 770 /* XXX - I don't like this */ 771 if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 || 772 k->p_stat == SZOMB || k->p_stat == SDEAD) 773 return (0.0); 774 if (rawcpu) 775 return (100.0 * fxtofl(k->p_pctcpu)); 776 return (100.0 * fxtofl(k->p_pctcpu) / 777 (1.0 - exp(k->p_swtime * log(ccpu)))); 778 } 779 780 void 781 pcpu(k, ve, mode) 782 struct kinfo_proc2 *k; 783 VARENT *ve; 784 int mode; 785 { 786 VAR *v; 787 788 v = ve->var; 789 doubleprintorsetwidth(v, getpcpu(k), 1, mode); 790 } 791 792 double 793 getpmem(k) 794 struct kinfo_proc2 *k; 795 { 796 static int failure; 797 double fracmem; 798 int szptudot; 799 800 if (!nlistread) 801 failure = (kd) ? donlist() : 1; 802 if (failure) 803 return (0.0); 804 805 if ((k->p_flag & P_INMEM) == 0) 806 return (0.0); 807 /* XXX want pmap ptpages, segtab, etc. (per architecture) */ 808 szptudot = USPACE/getpagesize(); 809 /* XXX don't have info about shared */ 810 fracmem = ((float)k->p_vm_rssize + szptudot)/mempages; 811 return (100.0 * fracmem); 812 } 813 814 void 815 pmem(k, ve, mode) 816 struct kinfo_proc2 *k; 817 VARENT *ve; 818 int mode; 819 { 820 VAR *v; 821 822 v = ve->var; 823 doubleprintorsetwidth(v, getpmem(k), 1, mode); 824 } 825 826 void 827 pagein(k, ve, mode) 828 struct kinfo_proc2 *k; 829 VARENT *ve; 830 int mode; 831 { 832 VAR *v; 833 834 v = ve->var; 835 intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode); 836 } 837 838 void 839 maxrss(k, ve, mode) 840 struct kinfo_proc2 *k; 841 VARENT *ve; 842 int mode; 843 { 844 VAR *v; 845 846 v = ve->var; 847 /* No need to check width! */ 848 if (mode == PRINTMODE) 849 (void)printf("%*s", v->width, "-"); 850 } 851 852 void 853 tsize(k, ve, mode) 854 struct kinfo_proc2 *k; 855 VARENT *ve; 856 int mode; 857 { 858 VAR *v; 859 860 v = ve->var; 861 intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode); 862 } 863 864 /* 865 * Generic output routines. Print fields from various prototype 866 * structures. 867 */ 868 static void 869 printval(bp, v, mode) 870 void *bp; 871 VAR *v; 872 int mode; 873 { 874 static char ofmt[32] = "%"; 875 int width, vok, fmtlen; 876 char *fcp, *cp, *obuf; 877 enum type type; 878 long long val; 879 unsigned long long uval; 880 881 /* 882 * Note that the "INF127" check is nonsensical for types 883 * that are or can be signed. 884 */ 885 #define GET(type) (*(type *)bp) 886 #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) 887 888 #define VSIGN 1 889 #define VUNSIGN 2 890 #define VPTR 3 891 892 if (mode == WIDTHMODE) { 893 vok = 0; 894 switch (v->type) { 895 case CHAR: 896 val = GET(char); 897 vok = VSIGN; 898 break; 899 case UCHAR: 900 uval = CHK_INF127(GET(u_char)); 901 vok = VUNSIGN; 902 break; 903 case SHORT: 904 val = GET(short); 905 vok = VSIGN; 906 break; 907 case USHORT: 908 uval = CHK_INF127(GET(u_short)); 909 vok = VUNSIGN; 910 break; 911 case INT32: 912 val = GET(int32_t); 913 vok = VSIGN; 914 break; 915 case INT: 916 val = GET(int); 917 vok = VSIGN; 918 break; 919 case UINT: 920 case UINT32: 921 uval = CHK_INF127(GET(u_int)); 922 vok = VUNSIGN; 923 break; 924 case LONG: 925 val = GET(long); 926 vok = VSIGN; 927 break; 928 case ULONG: 929 uval = CHK_INF127(GET(u_long)); 930 vok = VUNSIGN; 931 break; 932 case KPTR: 933 uval = GET(u_long); 934 vok = VPTR; 935 break; 936 case KPTR24: 937 uval = GET(u_long) & 0xffffff; 938 vok = VPTR; 939 break; 940 default: 941 /* nothing... */; 942 } 943 switch (vok) { 944 case VSIGN: 945 if (val < 0 && val < v->longestn) { 946 fmtlen = (int)log10((double)-val) + 2; 947 v->longestn = val; 948 if (fmtlen > v->width) 949 v->width = fmtlen; 950 } else if (val > 0 && val > v->longestp) { 951 fmtlen = (int)log10((double)val) + 1; 952 v->longestp = val; 953 if (fmtlen > v->width) 954 v->width = fmtlen; 955 } 956 return; 957 case VUNSIGN: 958 if (uval > v->longestu) { 959 fmtlen = (int)log10((double)uval) + 1; 960 v->longestu = uval; 961 v->width = fmtlen; 962 } 963 return; 964 case VPTR: 965 fmtlen = 0; 966 while (uval > 0) { 967 uval >>= 4; 968 fmtlen++; 969 } 970 if (fmtlen > v->width) 971 v->width = fmtlen; 972 return; 973 } 974 } 975 976 width = v->width; 977 cp = ofmt + 1; 978 fcp = v->fmt; 979 if (v->flag & LJUST) 980 *cp++ = '-'; 981 *cp++ = '*'; 982 while ((*cp++ = *fcp++) != '\0') 983 continue; 984 985 switch (v->type) { 986 case INT32: 987 if (sizeof(int32_t) == sizeof(int)) 988 type = INT; 989 else if (sizeof(int32_t) == sizeof(long)) 990 type = LONG; 991 else 992 errx(1, "unknown conversion for type %d", v->type); 993 break; 994 case UINT32: 995 if (sizeof(u_int32_t) == sizeof(u_int)) 996 type = UINT; 997 else if (sizeof(u_int32_t) == sizeof(u_long)) 998 type = ULONG; 999 else 1000 errx(1, "unknown conversion for type %d", v->type); 1001 break; 1002 default: 1003 type = v->type; 1004 break; 1005 } 1006 1007 switch (type) { 1008 case CHAR: 1009 (void)printf(ofmt, width, GET(char)); 1010 return; 1011 case UCHAR: 1012 (void)printf(ofmt, width, CHK_INF127(GET(u_char))); 1013 return; 1014 case SHORT: 1015 (void)printf(ofmt, width, GET(short)); 1016 return; 1017 case USHORT: 1018 (void)printf(ofmt, width, CHK_INF127(GET(u_short))); 1019 return; 1020 case INT: 1021 (void)printf(ofmt, width, GET(int)); 1022 return; 1023 case UINT: 1024 (void)printf(ofmt, width, CHK_INF127(GET(u_int))); 1025 return; 1026 case LONG: 1027 (void)printf(ofmt, width, GET(long)); 1028 return; 1029 case ULONG: 1030 (void)printf(ofmt, width, CHK_INF127(GET(u_long))); 1031 return; 1032 case KPTR: 1033 (void)printf(ofmt, width, GET(u_long)); 1034 return; 1035 case KPTR24: 1036 (void)printf(ofmt, width, GET(u_long) & 0xffffff); 1037 return; 1038 case SIGLIST: 1039 { 1040 sigset_t *s = (sigset_t *)(void *)bp; 1041 size_t i; 1042 #define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0])) 1043 char buf[SIGSETSIZE * 8 + 1]; 1044 1045 for (i = 0; i < SIGSETSIZE; i++) 1046 (void)snprintf(&buf[i * 8], 9, "%.8x", 1047 s->__bits[(SIGSETSIZE - 1) - i]); 1048 1049 /* Skip leading zeroes */ 1050 for (i = 0; buf[i]; i++) 1051 if (buf[i] != '0') 1052 break; 1053 1054 if (buf[i] == '\0') 1055 i--; 1056 (void)asprintf(&obuf, ofmt, width, &buf[i]); 1057 } 1058 break; 1059 default: 1060 errx(1, "unknown type %d", v->type); 1061 } 1062 if (obuf == NULL) 1063 err(1, "%s", ""); 1064 if (mode == WIDTHMODE) { 1065 /* Skip leading spaces. */ 1066 cp = strrchr(obuf, ' '); 1067 if (cp == NULL) 1068 cp = obuf; 1069 else 1070 cp++; /* skip last space */ 1071 } 1072 else 1073 cp = obuf; 1074 strprintorsetwidth(v, cp, mode); 1075 free(obuf); 1076 #undef GET 1077 #undef CHK_INF127 1078 } 1079 1080 void 1081 pvar(k, ve, mode) 1082 struct kinfo_proc2 *k; 1083 VARENT *ve; 1084 int mode; 1085 { 1086 VAR *v; 1087 1088 v = ve->var; 1089 printval((char *)k + v->off, v, mode); 1090 } 1091