1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif /* not lint */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)pstat.c 5.27 (Berkeley) 08/31/90"; 15 #endif /* not lint */ 16 17 /* 18 * Print system stuff 19 */ 20 #include <sys/param.h> 21 #include <sys/user.h> 22 #include <sys/proc.h> 23 #include <sys/text.h> 24 #include <sys/time.h> 25 #include <sys/vnode.h> 26 #include <sys/map.h> 27 #define KERNEL 28 #define NFS 29 #include <sys/file.h> 30 #include <sys/mount.h> 31 #include <ufs/quota.h> 32 #include <ufs/inode.h> 33 #include <sys/stat.h> 34 #include <nfs/nfsv2.h> 35 #include <nfs/nfs.h> 36 #include <nfs/nfsnode.h> 37 #include <sys/ioctl.h> 38 #include <sys/tty.h> 39 #undef KERNEL 40 #include <sys/conf.h> 41 #include <sys/vm.h> 42 #include <machine/pte.h> 43 44 #include <kvm.h> 45 #include <nlist.h> 46 #include <stdio.h> 47 #include "pathnames.h" 48 49 #define mask(x) (x&0377) 50 #define clear(x) ((int)x &~ KERNBASE) 51 52 char *fnlist = NULL; 53 char *fcore = NULL; 54 55 struct nlist nl[] = { 56 #define STEXT 0 57 { "_text" }, 58 #define SCONS 1 59 { "_cons" }, 60 #define SPROC 2 61 { "_proc" }, 62 #define SFIL 3 63 { "_file" }, 64 #define SWAPMAP 4 65 { "_swapmap" }, 66 #define SNPROC 5 67 { "_nproc" }, 68 #define SNTEXT 6 69 { "_ntext" }, 70 #define SNFILE 7 71 { "_nfile" }, 72 #define SNSWAPMAP 8 73 { "_nswapmap" }, 74 #define SPTY 9 75 { "_pt_tty" }, 76 #define SDMMIN 10 77 { "_dmmin" }, 78 #define SDMMAX 11 79 { "_dmmax" }, 80 #define SNSWDEV 12 81 { "_nswdev" }, 82 #define SSWDEVT 13 83 { "_swdevt" }, 84 #define SNPTY 14 85 { "_npty" }, 86 #ifdef vax 87 #define SDZ (SNPTY+1) 88 { "_dz_tty" }, 89 #define SNDZ (SNPTY+2) 90 { "_dz_cnt" }, 91 #define SDMF (SNPTY+3) 92 { "_dmf_tty" }, 93 #define SNDMF (SNPTY+4) 94 { "_ndmf" }, 95 #define SDH (SNPTY+5) 96 { "_dh11" }, 97 #define SNDH (SNPTY+6) 98 { "_ndh11" }, 99 #define SDHU (SNPTY+7) 100 { "_dhu_tty" }, 101 #define SNDHU (SNPTY+8) 102 { "_ndhu" }, 103 #define SDMZ (SNPTY+9) 104 { "_dmz_tty" }, 105 #define SNDMZ (SNPTY+10) 106 { "_ndmz" }, 107 #define SQD (SNPTY+11) 108 { "_qd_tty" }, 109 #define SNQD (SNPTY+12) 110 { "_nNQD" }, 111 #endif 112 #ifdef tahoe 113 #define SVX (SNPTY+1) 114 { "_vx_tty" }, 115 #define SNVX (SNPTY+2) 116 { "_nvx" }, 117 #define SMP (SNPTY+3) 118 { "_mp_tty" }, 119 #define SNMP (SNPTY+4) 120 { "_nmp" }, 121 #endif 122 { "" } 123 }; 124 125 int vnof; 126 int txtf; 127 int prcf; 128 int ttyf; 129 int usrf; 130 int upid; 131 int filf; 132 int swpf; 133 int totflg; 134 char partab[1]; 135 struct cdevsw cdevsw[1]; 136 struct bdevsw bdevsw[1]; 137 int allflg; 138 int nflg; 139 u_long getword(); 140 off_t mkphys(); 141 142 char *Program; 143 144 main(argc, argv) 145 int argc; 146 char **argv; 147 { 148 extern char *optarg; 149 extern int optind; 150 int ch; 151 152 Program = argv[0]; 153 while ((ch = getopt(argc, argv, "TafvikptU:sxnu")) != EOF) 154 switch((char)ch) { 155 case 'T': 156 totflg++; 157 break; 158 case 'a': 159 allflg++; 160 /*FALLTHROUGH*/ 161 case 'p': 162 prcf++; 163 break; 164 case 'f': 165 filf++; 166 break; 167 case 'v': 168 case 'i': 169 vnof++; 170 break; 171 case 't': 172 ttyf++; 173 break; 174 case 'U': 175 usrf++; 176 sscanf(optarg, "%d", &upid); 177 break; 178 case 's': 179 swpf++; 180 break; 181 case 'x': 182 txtf++; 183 break; 184 case 'n': 185 nflg++; 186 break; 187 case 'u': 188 fprintf(stderr, "pstat: use [ -U pid ] for -u\n"); 189 exit(1); 190 case '?': 191 default: 192 fprintf(stderr, "usage: pstat -[Tafiptsx] [-U [pid]] [system] [core]\n"); 193 exit(1); 194 } 195 argc -= optind; 196 argv += optind; 197 198 if (argc > 1) 199 fcore = argv[1]; 200 if (argc > 0) 201 fnlist = argv[0]; 202 if (kvm_openfiles(fnlist, fcore, NULL) == -1) { 203 syserror("kvm_openfiles: %s", kvm_geterr()); 204 exit(1); 205 } 206 if (kvm_nlist(nl) != 0) { 207 syserror("kvm_nlist: %s", kvm_geterr()); 208 exit(1); 209 } 210 if (!(filf | totflg | vnof | prcf | txtf | ttyf | usrf | swpf)) { 211 printf("pstat: one or more of -[aivxptfsU] is required\n"); 212 exit(1); 213 } 214 if (filf||totflg) 215 dofile(); 216 if (vnof||totflg) 217 dovnode(); 218 if (prcf||totflg) 219 doproc(); 220 if (txtf||totflg) 221 dotext(); 222 if (ttyf) 223 dotty(); 224 if (usrf) 225 dousr(); 226 if (swpf||totflg) 227 doswap(); 228 } 229 230 struct e_vnode { 231 struct vnode *avnode; 232 struct vnode vnode; 233 }; 234 235 dovnode() 236 { 237 register struct e_vnode *e_vnodebase, *endvnode, *evp; 238 register struct vnode *vp; 239 register struct mount *maddr = NULL, *mp; 240 register struct inode *ip; 241 int numvnodes; 242 struct e_vnode *loadvnodes(); 243 struct mount *getmnt(); 244 245 e_vnodebase = loadvnodes(&numvnodes); 246 if (totflg) { 247 printf("%7d vnodes\n", numvnodes); 248 return; 249 } 250 endvnode = e_vnodebase + numvnodes; 251 printf("%d active vnodes\n", numvnodes); 252 253 254 #define ST mp->mnt_stat 255 for (evp = e_vnodebase; evp < endvnode; evp++) { 256 vp = &evp->vnode; 257 if (vp->v_mount != maddr) { 258 /* 259 * New filesystem 260 */ 261 if ((mp = getmnt(vp->v_mount)) == NULL) 262 continue; 263 maddr = vp->v_mount; 264 mount_print(mp); 265 vnode_header(); 266 switch(ST.f_type) { 267 case MOUNT_UFS: 268 case MOUNT_MFS: 269 ufs_header(); 270 break; 271 case MOUNT_NFS: 272 nfs_header(); 273 break; 274 case MOUNT_NONE: 275 case MOUNT_PC: 276 default: 277 break; 278 } 279 printf("\n"); 280 } 281 vnode_print(evp->avnode, vp); 282 switch(ST.f_type) { 283 case MOUNT_UFS: 284 case MOUNT_MFS: 285 ufs_print(vp); 286 break; 287 case MOUNT_NFS: 288 nfs_print(vp); 289 break; 290 case MOUNT_NONE: 291 case MOUNT_PC: 292 default: 293 break; 294 } 295 printf("\n"); 296 } 297 free(e_vnodebase); 298 } 299 300 vnode_header() 301 { 302 printf("ADDR TYP VFLAG USE REF"); 303 } 304 305 vnode_print(avnode, vp) 306 struct vnode *avnode; 307 struct vnode *vp; 308 { 309 char *type, flags[16]; 310 char *fp = flags; 311 register flag; 312 313 /* 314 * set type 315 */ 316 switch(vp->v_type) { 317 case VNON: 318 type = "non"; break; 319 case VREG: 320 type = "reg"; break; 321 case VDIR: 322 type = "dir"; break; 323 case VBLK: 324 type = "blk"; break; 325 case VCHR: 326 type = "chr"; break; 327 case VLNK: 328 type = "lnk"; break; 329 case VSOCK: 330 type = "soc"; break; 331 case VFIFO: 332 type = "fif"; break; 333 case VBAD: 334 type = "bad"; break; 335 default: 336 type = "unk"; break; 337 } 338 /* 339 * gather flags 340 */ 341 flag = vp->v_flag; 342 if (flag & VROOT) 343 *fp++ = 'R'; 344 if (flag & VTEXT) 345 *fp++ = 'T'; 346 if (flag & VXLOCK) 347 *fp++ = 'L'; 348 if (flag & VXWANT) 349 *fp++ = 'W'; 350 if (flag & VEXLOCK) 351 *fp++ = 'E'; 352 if (flag & VSHLOCK) 353 *fp++ = 'S'; 354 if (flag & VLWAIT) 355 *fp++ = 'T'; 356 if (flag & VALIASED) 357 *fp++ = 'A'; 358 if (flag & VBWAIT) 359 *fp++ = 'B'; 360 if (flag == 0) 361 *fp++ = '-'; 362 *fp = '\0'; 363 /* 364 * print it 365 */ 366 printf("%8x %s %5s %4d %4d", 367 avnode, type, flags, vp->v_usecount, vp->v_holdcnt); 368 } 369 370 ufs_header() 371 { 372 printf(" FILEID IFLAG RDEV|SZ"); 373 } 374 375 ufs_print(vp) 376 struct vnode *vp; 377 { 378 struct inode *ip = VTOI(vp); 379 char flagbuf[16], *flags = flagbuf; 380 register flag; 381 char *name; 382 mode_t type; 383 extern char *devname(); 384 385 flag = ip->i_flag; 386 if (flag & ILOCKED) 387 *flags++ = 'L'; 388 if (flag & IWANT) 389 *flags++ = 'W'; 390 if (flag & IRENAME) 391 *flags++ = 'R'; 392 if (flag & IUPD) 393 *flags++ = 'U'; 394 if (flag & IACC) 395 *flags++ = 'A'; 396 if (flag & ICHG) 397 *flags++ = 'C'; 398 if (flag & IMOD) 399 *flags++ = 'M'; 400 if (flag & ISHLOCK) 401 *flags++ = 'S'; 402 if (flag & IEXLOCK) 403 *flags++ = 'E'; 404 if (flag & ILWAIT) 405 *flags++ = 'Z'; 406 if (flag == 0) 407 *flags++ = '-'; 408 *flags = '\0'; 409 410 printf(" %6d %5s", ip->i_number, flagbuf); 411 type = ip->i_mode & S_IFMT; 412 if (type == S_IFCHR || type == S_IFBLK) 413 if (nflg || ((name = devname(ip->i_rdev, type)) == NULL)) 414 printf(" %2d,%-2d", 415 major(ip->i_rdev), minor(ip->i_rdev)); 416 else 417 printf(" %7s", name); 418 else 419 printf(" %7d", ip->i_size); 420 } 421 422 nfs_header() 423 { 424 printf(" FILEID NFLAG RDEV|SZ"); 425 } 426 427 nfs_print(vp) 428 struct vnode *vp; 429 { 430 struct nfsnode *np = VTONFS(vp); 431 char flagbuf[16], *flags = flagbuf; 432 register flag; 433 char *name; 434 mode_t type; 435 extern char *devname(); 436 437 flag = np->n_flag; 438 if (flag & NLOCKED) 439 *flags++ = 'L'; 440 if (flag & NWANT) 441 *flags++ = 'W'; 442 if (flag & NMODIFIED) 443 *flags++ = 'M'; 444 if (flag & NWRITEERR) 445 *flags++ = 'E'; 446 if (flag == 0) 447 *flags++ = '-'; 448 *flags = '\0'; 449 450 #define VT np->n_vattr 451 printf(" %6d %5s", VT.va_fileid, flagbuf); 452 type = VT.va_mode & S_IFMT; 453 if (type == S_IFCHR || type == S_IFBLK) 454 if (nflg || ((name = devname(VT.va_rdev, type)) == NULL)) 455 printf(" %2d,%-2d", 456 major(VT.va_rdev), minor(VT.va_rdev)); 457 else 458 printf(" %7s", name); 459 else 460 printf(" %7d", np->n_size); 461 } 462 463 /* 464 * Given a pointer to a mount structure in kernel space, 465 * read it in and return a usable pointer to it. 466 */ 467 struct mount * 468 getmnt(maddr) 469 struct mount *maddr; 470 { 471 static struct mtab { 472 struct mtab *next; 473 struct mount *maddr; 474 struct mount mount; 475 } *mhead = NULL; 476 register struct mtab *mt; 477 478 for (mt = mhead; mt != NULL; mt = mt->next) 479 if (maddr == mt->maddr) 480 return (&mt->mount); 481 if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) { 482 error("out of memory"); 483 exit(1); 484 } 485 if (kvm_read((off_t)maddr, &mt->mount, sizeof(struct mount)) != 486 sizeof(struct mount)) { 487 error("can't read mount table at %x", maddr); 488 return (NULL); 489 } 490 mt->maddr = maddr; 491 mt->next = mhead; 492 mhead = mt; 493 return (&mt->mount); 494 } 495 496 mount_print(mp) 497 struct mount *mp; 498 { 499 char *type = "unknown"; 500 register flags; 501 502 #define ST mp->mnt_stat 503 printf("*** MOUNT "); 504 switch (ST.f_type) { 505 case MOUNT_NONE: 506 type = "none"; 507 break; 508 case MOUNT_UFS: 509 type = "ufs"; 510 break; 511 case MOUNT_NFS: 512 type = "nfs"; 513 break; 514 case MOUNT_MFS: 515 type = "mfs"; 516 break; 517 case MOUNT_PC: 518 type = "pc"; 519 break; 520 } 521 printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname); 522 if (flags = mp->mnt_flag) { 523 char *comma = "("; 524 525 putchar(' '); 526 /* user visable flags */ 527 if (flags & MNT_RDONLY) { 528 printf("%srdonly", comma); 529 flags &= ~MNT_RDONLY; 530 comma = ","; 531 } 532 if (flags & MNT_SYNCHRONOUS) { 533 printf("%ssynchronous", comma); 534 flags &= ~MNT_SYNCHRONOUS; 535 comma = ","; 536 } 537 if (flags & MNT_NOEXEC) { 538 printf("%snoexec", comma); 539 flags &= ~MNT_NOEXEC; 540 comma = ","; 541 } 542 if (flags & MNT_NOSUID) { 543 printf("%snosuid", comma); 544 flags &= ~MNT_NOSUID; 545 comma = ","; 546 } 547 if (flags & MNT_NODEV) { 548 printf("%snodev", comma); 549 flags &= ~MNT_NODEV; 550 comma = ","; 551 } 552 if (flags & MNT_EXPORTED) { 553 printf("%sexport", comma); 554 flags &= ~MNT_EXPORTED; 555 comma = ","; 556 } 557 if (flags & MNT_EXRDONLY) { 558 printf("%sexrdonly", comma); 559 flags &= ~MNT_EXRDONLY; 560 comma = ","; 561 } 562 if (flags & MNT_LOCAL) { 563 printf("%slocal", comma); 564 flags &= ~MNT_LOCAL; 565 comma = ","; 566 } 567 if (flags & MNT_QUOTA) { 568 printf("%squota", comma); 569 flags &= ~MNT_QUOTA; 570 comma = ","; 571 } 572 /* filesystem control flags */ 573 if (flags & MNT_UPDATE) { 574 printf("%supdate", comma); 575 flags &= ~MNT_UPDATE; 576 comma = ","; 577 } 578 if (flags & MNT_MLOCK) { 579 printf("%slock", comma); 580 flags &= ~MNT_MLOCK; 581 comma = ","; 582 } 583 if (flags & MNT_MWAIT) { 584 printf("%swait", comma); 585 flags &= ~MNT_MWAIT; 586 comma = ","; 587 } 588 if (flags & MNT_MPBUSY) { 589 printf("%sbusy", comma); 590 flags &= ~MNT_MPBUSY; 591 comma = ","; 592 } 593 if (flags & MNT_MPWANT) { 594 printf("%swant", comma); 595 flags &= ~MNT_MPWANT; 596 comma = ","; 597 } 598 if (flags & MNT_UNMOUNT) { 599 printf("%sunmount", comma); 600 flags &= ~MNT_UNMOUNT; 601 comma = ","; 602 } 603 if (flags) 604 printf("%sunknown_flags:%x", flags); 605 printf(")"); 606 } 607 printf("\n"); 608 #undef ST 609 } 610 611 struct e_vnode * 612 loadvnodes(avnodes) 613 int *avnodes; 614 { 615 int ret, copysize, i; 616 struct e_vnode *vnodebase; 617 618 if (fcore != NULL) { 619 error("vnodes on dead kernel, not impl yet\n"); 620 exit(1); 621 } 622 if ((ret = getkerninfo(KINFO_VNODE, NULL, NULL, 0)) == -1) { 623 syserror("can't get estimate for kerninfo"); 624 exit(1); 625 } 626 copysize = ret; 627 if ((vnodebase = (struct e_vnode *)malloc(copysize)) 628 == NULL) { 629 error("out of memory"); 630 exit(1); 631 } 632 if ((ret = getkerninfo(KINFO_VNODE, vnodebase, ©size, 0)) 633 == -1) { 634 syserror("can't get vnode list"); 635 exit(1); 636 } 637 if (copysize % sizeof (struct e_vnode)) { 638 error("vnode size mismatch"); 639 error(1); 640 } 641 *avnodes = copysize / sizeof (struct e_vnode); 642 643 return (vnodebase); 644 } 645 646 u_long 647 getword(loc) 648 off_t loc; 649 { 650 u_long word; 651 652 kvm_read(loc, &word, sizeof (word)); 653 return (word); 654 } 655 656 putf(v, n) 657 { 658 if (v) 659 printf("%c", n); 660 else 661 printf(" "); 662 } 663 664 dotext() 665 { 666 register struct text *xp; 667 int ntext; 668 struct text *xtext, *atext; 669 int ntx, ntxca; 670 671 ntx = ntxca = 0; 672 ntext = getword(nl[SNTEXT].n_value); 673 xtext = (struct text *)calloc(ntext, sizeof (struct text)); 674 atext = (struct text *)getword(nl[STEXT].n_value); 675 if (ntext < 0 || ntext > 10000) { 676 fprintf(stderr, "number of texts is preposterous (%d)\n", 677 ntext); 678 return; 679 } 680 if (xtext == NULL) { 681 fprintf(stderr, "can't allocate memory for text table\n"); 682 return; 683 } 684 kvm_read(atext, xtext, ntext * sizeof (struct text)); 685 for (xp = xtext; xp < &xtext[ntext]; xp++) { 686 if (xp->x_vptr != NULL) 687 ntxca++; 688 if (xp->x_count != 0) 689 ntx++; 690 } 691 if (totflg) { 692 printf("%3d/%3d texts active, %3d used\n", ntx, ntext, ntxca); 693 return; 694 } 695 printf("%d/%d active texts, %d used\n", ntx, ntext, ntxca); 696 printf("\ 697 LOC FLAGS DADDR CADDR RSS SIZE VPTR CNT CCNT FORW BACK\n"); 698 for (xp = xtext; xp < &xtext[ntext]; xp++) { 699 if (xp->x_vptr == NULL) 700 continue; 701 printf("%8.1x", atext + (xp - xtext)); 702 printf(" "); 703 putf(xp->x_flag&XPAGV, 'P'); 704 putf(xp->x_flag&XTRC, 'T'); 705 putf(xp->x_flag&XWRIT, 'W'); 706 putf(xp->x_flag&XLOAD, 'L'); 707 putf(xp->x_flag&XLOCK, 'K'); 708 putf(xp->x_flag&XWANT, 'w'); 709 printf("%5x", xp->x_daddr[0]); 710 printf("%10x", xp->x_caddr); 711 printf("%5d", xp->x_rssize); 712 printf("%5d", xp->x_size); 713 printf("%10.1x", xp->x_vptr); 714 printf("%5d", xp->x_count&0377); 715 printf("%5d", xp->x_ccount); 716 printf("%10x", xp->x_forw); 717 printf("%9x", xp->x_back); 718 printf("\n"); 719 } 720 free(xtext); 721 } 722 723 doproc() 724 { 725 struct proc *xproc, *aproc; 726 int nproc; 727 register struct proc *pp; 728 register loc, np; 729 struct pte apte; 730 731 nproc = getword(nl[SNPROC].n_value); 732 xproc = (struct proc *)calloc(nproc, sizeof (struct proc)); 733 aproc = (struct proc *)getword(nl[SPROC].n_value); 734 if (nproc < 0 || nproc > 100000) { 735 fprintf(stderr, "number of procs is preposterous (%d)\n", 736 nproc); 737 return; 738 } 739 if (xproc == NULL) { 740 fprintf(stderr, "can't allocate memory for proc table\n"); 741 return; 742 } 743 kvm_read(aproc, xproc, nproc * sizeof (struct proc)); 744 np = 0; 745 for (pp=xproc; pp < &xproc[nproc]; pp++) 746 if (pp->p_stat) 747 np++; 748 if (totflg) { 749 printf("%3d/%3d processes\n", np, nproc); 750 return; 751 } 752 printf("%d/%d processes\n", np, nproc); 753 printf(" LOC S F POIP PRI SIG UID SLP TIM CPU NI PID PPID ADDR RSS SRSS SIZE WCHAN LINK TEXTP\n"); 754 for (pp=xproc; pp<&xproc[nproc]; pp++) { 755 if (pp->p_stat==0 && allflg==0) 756 continue; 757 printf("%8x", aproc + (pp - xproc)); 758 printf(" %2d", pp->p_stat); 759 printf(" %8x", pp->p_flag); 760 printf(" %4d", pp->p_poip); 761 printf(" %3d", pp->p_pri); 762 printf(" %8x", pp->p_sig); 763 printf(" %4d", pp->p_uid); 764 printf(" %3d", pp->p_slptime); 765 printf(" %3d", pp->p_time); 766 printf(" %4d", pp->p_cpu&0377); 767 printf(" %3d", pp->p_nice); 768 printf(" %6d", pp->p_pid); 769 printf(" %6d", pp->p_ppid); 770 /* 771 if (pp->p_flag & SLOAD) { 772 kvm_read(pp->p_addr, &apte, sizeof(apte)); 773 printf(" %8x", apte.pg_pfnum); 774 } else 775 printf(" %8x", pp->p_swaddr); 776 */ 777 printf(" %4x", pp->p_rssize); 778 printf(" %4x", pp->p_swrss); 779 printf(" %5x", pp->p_dsize+pp->p_ssize); 780 printf(" %7x", clear(pp->p_wchan)); 781 printf(" %7x", clear(pp->p_link)); 782 printf(" %7x", clear(pp->p_textp)); 783 printf("\n"); 784 } 785 free(xproc); 786 } 787 788 char mesg[] = " LINE RAW CAN OUT RCC CCC OCC HWT LWT ADDR COL STATE PGID DISC\n"; 789 int ttyspace = 128; 790 struct tty *tty; 791 792 dotty() 793 { 794 795 if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) { 796 printf("pstat: out of memory\n"); 797 return; 798 } 799 printf("1 cons\n"); 800 kvm_read((long)nl[SCONS].n_value, tty, sizeof(*tty)); 801 printf(mesg); 802 ttyprt(&tty[0], 0); 803 #ifdef vax 804 if (nl[SNQD].n_type != 0) 805 doqdss(); 806 if (nl[SNDZ].n_type != 0) 807 dottytype("dz", SDZ, SNDZ); 808 if (nl[SNDH].n_type != 0) 809 dottytype("dh", SDH, SNDH); 810 if (nl[SNDMF].n_type != 0) 811 dottytype("dmf", SDMF, SNDMF); 812 if (nl[SNDHU].n_type != 0) 813 dottytype("dhu", SDHU, SNDHU); 814 if (nl[SNDMZ].n_type != 0) 815 dottytype("dmz", SDMZ, SNDMZ); 816 #endif 817 #ifdef tahoe 818 if (nl[SNVX].n_type != 0) 819 dottytype("vx", SVX, SNVX); 820 if (nl[SNMP].n_type != 0) 821 dottytype("mp", SMP, SNMP); 822 #endif 823 if (nl[SNPTY].n_type != 0) 824 dottytype("pty", SPTY, SNPTY); 825 } 826 827 /* 828 * Special case the qdss: there are 4 ttys per qdss, 829 * but only the first of each is used as a tty. 830 */ 831 #ifdef vax 832 doqdss() 833 { 834 int nqd; 835 register struct tty *tp; 836 837 kvm_read((long)nl[SNQD].n_value, &nqd, sizeof(nqd)); 838 printf("%d qd\n", nqd); 839 kvm_read((long)nl[SQD].n_value, tty, nqd * sizeof(struct tty) * 4); 840 printf(mesg); 841 for (tp = tty; tp < &tty[nqd * 4]; tp += 4) 842 ttyprt(tp, tp - tty); 843 } 844 #endif 845 846 dottytype(name, type, number) 847 char *name; 848 { 849 int ntty; 850 register struct tty *tp; 851 extern char *realloc(); 852 853 if (tty == (struct tty *)0) 854 return; 855 kvm_read((long)nl[number].n_value, &ntty, sizeof(ntty)); 856 printf("%d %s lines\n", ntty, name); 857 if (ntty > ttyspace) { 858 ttyspace = ntty; 859 if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) { 860 printf("pstat: out of memory\n"); 861 return; 862 } 863 } 864 kvm_read((long)nl[type].n_value, tty, ntty * sizeof(struct tty)); 865 printf(mesg); 866 for (tp = tty; tp < &tty[ntty]; tp++) 867 ttyprt(tp, tp - tty); 868 } 869 870 struct { 871 int flag; 872 char val; 873 } ttystates[] = { 874 TS_WOPEN, 'W', 875 TS_ISOPEN, 'O', 876 TS_CARR_ON, 'C', 877 TS_TIMEOUT, 'T', 878 TS_FLUSH, 'F', 879 TS_BUSY, 'B', 880 TS_ASLEEP, 'A', 881 TS_XCLUDE, 'X', 882 TS_TTSTOP, 'S', 883 TS_HUPCLS, 'H', 884 TS_TBLOCK, 'K', 885 TS_RCOLL, 'R', 886 TS_WCOLL, 'I', /* running short on letters ! */ 887 TS_ASYNC, 'Y', 888 TS_BKSL, 'D', 889 TS_ERASE, 'E', 890 TS_LNCH, 'L', 891 TS_TYPEN, 'P', 892 TS_CNTTB, 'N', 893 0, 0 894 }; 895 896 ttyprt(atp, line) 897 struct tty *atp; 898 { 899 register struct tty *tp; 900 char state[20]; 901 register i, j; 902 char *name; 903 extern char *devname(); 904 pid_t pgid; 905 906 tp = atp; 907 if (nflg || tp->t_dev == 0 || /* XXX */ 908 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 909 printf("%7d ", line); 910 else 911 printf("%7s ", name); 912 printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 913 printf("%3d %6d %6d %6d %4d %3d %8x %3d ", tp->t_outq.c_cc, 914 tp->t_rawcc, tp->t_cancc, tp->t_outcc, 915 tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col); 916 for (i = j = 0; ttystates[i].flag; i++) 917 if (tp->t_state&ttystates[i].flag) 918 state[j++] = ttystates[i].val; 919 state[j] = '\0'; 920 printf("%-4s ", state); 921 if (tp->t_pgrp == NULL || kvm_read(&tp->t_pgrp->pg_id, &pgid, 922 sizeof (pid_t)) != sizeof (pid_t)) 923 pgid = 0; 924 printf("%6d ", pgid); 925 switch (tp->t_line) { 926 927 case 0: 928 printf("term\n"); 929 break; 930 931 case TABLDISC: 932 printf("tab\n"); 933 break; 934 935 case SLIPDISC: 936 printf("slip\n"); 937 break; 938 939 default: 940 printf("%d\n", tp->t_line); 941 } 942 } 943 944 dousr() 945 { 946 register struct user *up; 947 register i, j, *ip; 948 register struct nameidata *nd; 949 struct proc *p; 950 int ret; 951 952 if ((ret = kvm_getprocs(KINFO_PROC_PID, upid)) != 1) { 953 if (ret == -1) 954 error("kvm_getproc: %s", kvm_geterr()); 955 else 956 error("can't locate process %d", upid); 957 return (1); 958 } 959 if ((p = kvm_nextproc()) == NULL) { 960 error("kvm_nextproc: %s", kvm_geterr()); 961 return (1); 962 } 963 if ((up = kvm_getu(p)) == NULL) { 964 error("kvm_getu: %s", kvm_geterr()); 965 return (1); 966 } 967 nd = &up->u_nd; 968 printf("pcb"); 969 ip = (int *)&up->u_pcb; 970 i = 0; 971 while (ip < (int *)((char *)&up->u_pcb + sizeof (struct pcb))) { 972 if (i%4 == 0) 973 putchar('\t'); 974 printf("%#10x ", *ip++); 975 if (i%4 == 3) 976 putchar('\n'); 977 i++; 978 } 979 if (i%4) 980 putchar('\n'); 981 printf("procp\t%#x\n", up->u_procp); 982 printf("ar0\t%#x\n", up->u_ar0); 983 printf("sizes\ttext %d data %d stack %d\n", 984 up->u_tsize, up->u_dsize, up->u_ssize); 985 /* DMAPS */ 986 printf("ssave"); 987 for (i=0; i<sizeof(label_t)/sizeof(int); i++) { 988 if (i%5==0) 989 printf("\t"); 990 printf("%#11x", up->u_ssave.val[i]); 991 if (i%5==4) 992 printf("\n"); 993 } 994 if (i%5) 995 printf("\n"); 996 printf("odsize\t%#x\n", up->u_odsize); 997 printf("ossize\t%#x\n", up->u_ossize); 998 printf("outime\t%d\n", up->u_outime); 999 printf("mmap\t%#x\n", up->u_mmap); 1000 printf("sigs"); 1001 for (i=0; i<NSIG; i++) { 1002 if (i % 8 == 0) 1003 printf("\t"); 1004 printf("%#x ", up->u_signal[i]); 1005 if (i % 8 == 7) 1006 printf("\n"); 1007 } 1008 if (i % 8) 1009 printf("\n"); 1010 printf("sigmask"); 1011 for (i=0; i<NSIG; i++) { 1012 if (i % 8 == 0) 1013 printf("\t"); 1014 printf("%#x ", up->u_sigmask[i]); 1015 if (i % 8 == 7) 1016 printf("\n"); 1017 } 1018 if (i % 8) 1019 printf("\n"); 1020 printf("sigonstack\t%#x\n", up->u_sigonstack); 1021 printf("sigintr\t%#x\n", up->u_sigintr); 1022 printf("oldmask\t%#x\n", up->u_oldmask); 1023 printf("sigstack\t%#x %#x\n", 1024 up->u_sigstack.ss_sp, up->u_sigstack.ss_onstack); 1025 printf("sig\t%#x\n", up->u_sig); 1026 printf("code\t%#x\n", up->u_code); 1027 printf("file"); 1028 for (i=0; i<NOFILE; i++) { 1029 if (i % 6 == 0) 1030 printf("\t"); 1031 printf("%#11x", up->u_ofile[i]); 1032 if (i % 6 == 5) 1033 printf("\n"); 1034 } 1035 if (i % 6) 1036 printf("\n"); 1037 printf("pofile"); 1038 for (i=0; i<NOFILE; i++) { 1039 if (i % 6 == 0) 1040 printf("\t"); 1041 printf("%#11x", up->u_pofile[i]); 1042 if (i % 6 == 5) 1043 printf("\n"); 1044 } 1045 if (i % 6) 1046 printf("\n"); 1047 printf("lastfile\t%d\n", up->u_lastfile); 1048 printf("cmask\t%#o\n", up->u_cmask); 1049 /* RUSAGES */ 1050 /* TIMERS */ 1051 printf("start\t%ld secs %ld usecs\n", 1052 up->u_start.tv_sec, up->u_start.tv_usec); 1053 printf("acflag\t%#x\n", up->u_acflag); 1054 printf("prof\t%#x %#x %#x %#x\n", up->u_prof.pr_base, up->u_prof.pr_size, 1055 up->u_prof.pr_off, up->u_prof.pr_scale); 1056 printf("ru\t"); 1057 ip = (int *)&up->u_ru; 1058 for (i = 0; i < sizeof(up->u_ru)/sizeof(int); i++) 1059 printf("%ld ", ip[i]); 1060 printf("\n"); 1061 ip = (int *)&up->u_cru; 1062 printf("cru\t"); 1063 for (i = 0; i < sizeof(up->u_cru)/sizeof(int); i++) 1064 printf("%ld ", ip[i]); 1065 printf("\n"); 1066 /* NAMEI */ 1067 } 1068 1069 oatoi(s) 1070 char *s; 1071 { 1072 register v; 1073 1074 v = 0; 1075 while (*s) 1076 v = (v<<3) + *s++ - '0'; 1077 return(v); 1078 } 1079 1080 dofile() 1081 { 1082 int nfile; 1083 struct file *xfile, *afile; 1084 register struct file *fp; 1085 register nf; 1086 int loc; 1087 static char *dtypes[] = { "???", "inode", "socket" }; 1088 1089 nf = 0; 1090 nfile = getword(nl[SNFILE].n_value); 1091 xfile = (struct file *)calloc(nfile, sizeof (struct file)); 1092 afile = (struct file *)getword(nl[SFIL].n_value); 1093 if (nfile < 0 || nfile > 100000) { 1094 fprintf(stderr, "number of files is preposterous (%d)\n", 1095 nfile); 1096 return; 1097 } 1098 if (xfile == NULL) { 1099 fprintf(stderr, "can't allocate memory for file table\n"); 1100 return; 1101 } 1102 kvm_read(afile, xfile, nfile * sizeof (struct file)); 1103 for (fp=xfile; fp < &xfile[nfile]; fp++) 1104 if (fp->f_count) 1105 nf++; 1106 if (totflg) { 1107 printf("%3d/%3d files\n", nf, nfile); 1108 return; 1109 } 1110 printf("%d/%d open files\n", nf, nfile); 1111 printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 1112 for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) { 1113 if (fp->f_count==0) 1114 continue; 1115 printf("%x ", loc); 1116 if (fp->f_type <= DTYPE_SOCKET) 1117 printf("%-8.8s", dtypes[fp->f_type]); 1118 else 1119 printf("%8d", fp->f_type); 1120 putf(fp->f_flag&FREAD, 'R'); 1121 putf(fp->f_flag&FWRITE, 'W'); 1122 putf(fp->f_flag&FAPPEND, 'A'); 1123 putf(fp->f_flag&FSHLOCK, 'S'); 1124 putf(fp->f_flag&FEXLOCK, 'X'); 1125 putf(fp->f_flag&FASYNC, 'I'); 1126 printf(" %3d", mask(fp->f_count)); 1127 printf(" %3d", mask(fp->f_msgcount)); 1128 printf(" %8.1x", fp->f_data); 1129 if (fp->f_offset < 0) 1130 printf(" %x\n", fp->f_offset); 1131 else 1132 printf(" %ld\n", fp->f_offset); 1133 } 1134 free(xfile); 1135 } 1136 1137 int dmmin, dmmax, nswdev; 1138 1139 doswap() 1140 { 1141 struct proc *proc; 1142 int nproc; 1143 struct text *xtext; 1144 int ntext; 1145 struct map *swapmap; 1146 int nswapmap; 1147 struct swdevt *swdevt, *sw; 1148 register struct proc *pp; 1149 int nswap, used, tused, free, waste; 1150 int db, sb; 1151 register struct mapent *me; 1152 register struct text *xp; 1153 int i, j; 1154 long rmalloc(); 1155 1156 nproc = getword(nl[SNPROC].n_value); 1157 ntext = getword(nl[SNTEXT].n_value); 1158 if (nproc < 0 || nproc > 10000 || ntext < 0 || ntext > 10000) { 1159 fprintf(stderr, "number of procs/texts is preposterous (%d, %d)\n", 1160 nproc, ntext); 1161 return; 1162 } 1163 proc = (struct proc *)calloc(nproc, sizeof (struct proc)); 1164 if (proc == NULL) { 1165 fprintf(stderr, "can't allocate memory for proc table\n"); 1166 exit(1); 1167 } 1168 xtext = (struct text *)calloc(ntext, sizeof (struct text)); 1169 if (xtext == NULL) { 1170 fprintf(stderr, "can't allocate memory for text table\n"); 1171 exit(1); 1172 } 1173 nswapmap = getword(nl[SNSWAPMAP].n_value); 1174 swapmap = (struct map *)calloc(nswapmap, sizeof (struct map)); 1175 if (swapmap == NULL) { 1176 fprintf(stderr, "can't allocate memory for swapmap\n"); 1177 exit(1); 1178 } 1179 nswdev = getword(nl[SNSWDEV].n_value); 1180 swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt)); 1181 if (swdevt == NULL) { 1182 fprintf(stderr, "can't allocate memory for swdevt table\n"); 1183 exit(1); 1184 } 1185 kvm_read(nl[SSWDEVT].n_value, swdevt, 1186 nswdev * sizeof (struct swdevt)); 1187 kvm_read(getword(nl[SPROC].n_value), proc, 1188 nproc * sizeof (struct proc)); 1189 kvm_read(getword(nl[STEXT].n_value), xtext, 1190 ntext * sizeof (struct text)); 1191 kvm_read(getword(nl[SWAPMAP].n_value), swapmap, 1192 nswapmap * sizeof (struct map)); 1193 1194 swapmap->m_name = "swap"; 1195 swapmap->m_limit = (struct mapent *)&swapmap[nswapmap]; 1196 dmmin = getword(nl[SDMMIN].n_value); 1197 dmmax = getword(nl[SDMMAX].n_value); 1198 nswap = 0; 1199 for (sw = swdevt; sw < &swdevt[nswdev]; sw++) 1200 if (sw->sw_freed) 1201 nswap += sw->sw_nblks; 1202 free = 0; 1203 for (me = (struct mapent *)(swapmap+1); 1204 me < (struct mapent *)&swapmap[nswapmap]; me++) 1205 free += me->m_size; 1206 tused = 0; 1207 for (xp = xtext; xp < &xtext[ntext]; xp++) 1208 if (xp->x_vptr!=NULL) { 1209 tused += ctod(clrnd(xp->x_size)); 1210 if (xp->x_flag & XPAGV) 1211 tused += ctod(clrnd(ctopt(xp->x_size))); 1212 } 1213 used = tused; 1214 waste = 0; 1215 for (pp = proc; pp < &proc[nproc]; pp++) { 1216 if (pp->p_stat == 0 || pp->p_stat == SZOMB) 1217 continue; 1218 if (pp->p_flag & SSYS) 1219 continue; 1220 db = ctod(pp->p_dsize), sb = up(db); 1221 used += sb; 1222 waste += sb - db; 1223 db = ctod(pp->p_ssize), sb = up(db); 1224 used += sb; 1225 waste += sb - db; 1226 if ((pp->p_flag&SLOAD) == 0) 1227 used += ctod(vusize(pp)); 1228 } 1229 if (totflg) { 1230 #define btok(x) ((x) / (1024 / DEV_BSIZE)) 1231 printf("%3d/%3d 00k swap\n", 1232 btok(used/100), btok((used+free)/100)); 1233 return; 1234 } 1235 printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n", 1236 btok(used), btok(tused), btok(free), btok(waste), 1237 /* a dmmax/2 block goes to argmap */ 1238 btok(nswap - dmmax/2 - (used + free))); 1239 printf("avail: "); 1240 for (i = dmmax; i >= dmmin; i /= 2) { 1241 j = 0; 1242 while (rmalloc(swapmap, i) != 0) 1243 j++; 1244 if (j) printf("%d*%dk ", j, btok(i)); 1245 } 1246 free = 0; 1247 for (me = (struct mapent *)(swapmap+1); 1248 me < (struct mapent *)&swapmap[nswapmap]; me++) 1249 free += me->m_size; 1250 printf("%d*1k\n", btok(free)); 1251 } 1252 1253 up(size) 1254 register int size; 1255 { 1256 register int i, block; 1257 1258 i = 0; 1259 block = dmmin; 1260 while (i < size) { 1261 i += block; 1262 if (block < dmmax) 1263 block *= 2; 1264 } 1265 return (i); 1266 } 1267 1268 /* 1269 * Compute number of pages to be allocated to the u. area 1270 * and data and stack area page tables, which are stored on the 1271 * disk immediately after the u. area. 1272 */ 1273 vusize(p) 1274 register struct proc *p; 1275 { 1276 register int tsz = p->p_tsize / NPTEPG; 1277 1278 /* 1279 * We do not need page table space on the disk for page 1280 * table pages wholly containing text. 1281 */ 1282 return (clrnd(UPAGES + 1283 clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz)); 1284 } 1285 1286 /* 1287 * Allocate 'size' units from the given 1288 * map. Return the base of the allocated space. 1289 * In a map, the addresses are increasing and the 1290 * list is terminated by a 0 size. 1291 * 1292 * Algorithm is first-fit. 1293 * 1294 * This routine knows about the interleaving of the swapmap 1295 * and handles that. 1296 */ 1297 long 1298 rmalloc(mp, size) 1299 register struct map *mp; 1300 long size; 1301 { 1302 register struct mapent *ep = (struct mapent *)(mp+1); 1303 register int addr; 1304 register struct mapent *bp; 1305 swblk_t first, rest; 1306 1307 if (size <= 0 || size > dmmax) 1308 return (0); 1309 /* 1310 * Search for a piece of the resource map which has enough 1311 * free space to accomodate the request. 1312 */ 1313 for (bp = ep; bp->m_size; bp++) { 1314 if (bp->m_size >= size) { 1315 /* 1316 * If allocating from swapmap, 1317 * then have to respect interleaving 1318 * boundaries. 1319 */ 1320 if (nswdev > 1 && 1321 (first = dmmax - bp->m_addr%dmmax) < bp->m_size) { 1322 if (bp->m_size - first < size) 1323 continue; 1324 addr = bp->m_addr + first; 1325 rest = bp->m_size - first - size; 1326 bp->m_size = first; 1327 if (rest) 1328 rmfree(mp, rest, addr+size); 1329 return (addr); 1330 } 1331 /* 1332 * Allocate from the map. 1333 * If there is no space left of the piece 1334 * we allocated from, move the rest of 1335 * the pieces to the left. 1336 */ 1337 addr = bp->m_addr; 1338 bp->m_addr += size; 1339 if ((bp->m_size -= size) == 0) { 1340 do { 1341 bp++; 1342 (bp-1)->m_addr = bp->m_addr; 1343 } while ((bp-1)->m_size = bp->m_size); 1344 } 1345 if (addr % CLSIZE) 1346 return (0); 1347 return (addr); 1348 } 1349 } 1350 return (0); 1351 } 1352 1353 /* 1354 * Free the previously allocated space at addr 1355 * of size units into the specified map. 1356 * Sort addr into map and combine on 1357 * one or both ends if possible. 1358 */ 1359 rmfree(mp, size, addr) 1360 struct map *mp; 1361 long size, addr; 1362 { 1363 struct mapent *firstbp; 1364 register struct mapent *bp; 1365 register int t; 1366 1367 /* 1368 * Both address and size must be 1369 * positive, or the protocol has broken down. 1370 */ 1371 if (addr <= 0 || size <= 0) 1372 goto badrmfree; 1373 /* 1374 * Locate the piece of the map which starts after the 1375 * returned space (or the end of the map). 1376 */ 1377 firstbp = bp = (struct mapent *)(mp + 1); 1378 for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 1379 continue; 1380 /* 1381 * If the piece on the left abuts us, 1382 * then we should combine with it. 1383 */ 1384 if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1385 /* 1386 * Check no overlap (internal error). 1387 */ 1388 if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1389 goto badrmfree; 1390 /* 1391 * Add into piece on the left by increasing its size. 1392 */ 1393 (bp-1)->m_size += size; 1394 /* 1395 * If the combined piece abuts the piece on 1396 * the right now, compress it in also, 1397 * by shifting the remaining pieces of the map over. 1398 */ 1399 if (bp->m_addr && addr+size >= bp->m_addr) { 1400 if (addr+size > bp->m_addr) 1401 goto badrmfree; 1402 (bp-1)->m_size += bp->m_size; 1403 while (bp->m_size) { 1404 bp++; 1405 (bp-1)->m_addr = bp->m_addr; 1406 (bp-1)->m_size = bp->m_size; 1407 } 1408 } 1409 goto done; 1410 } 1411 /* 1412 * Don't abut on the left, check for abutting on 1413 * the right. 1414 */ 1415 if (addr+size >= bp->m_addr && bp->m_size) { 1416 if (addr+size > bp->m_addr) 1417 goto badrmfree; 1418 bp->m_addr -= size; 1419 bp->m_size += size; 1420 goto done; 1421 } 1422 /* 1423 * Don't abut at all. Make a new entry 1424 * and check for map overflow. 1425 */ 1426 do { 1427 t = bp->m_addr; 1428 bp->m_addr = addr; 1429 addr = t; 1430 t = bp->m_size; 1431 bp->m_size = size; 1432 bp++; 1433 } while (size = t); 1434 /* 1435 * Segment at bp is to be the delimiter; 1436 * If there is not room for it 1437 * then the table is too full 1438 * and we must discard something. 1439 */ 1440 if (bp+1 > mp->m_limit) { 1441 /* 1442 * Back bp up to last available segment. 1443 * which contains a segment already and must 1444 * be made into the delimiter. 1445 * Discard second to last entry, 1446 * since it is presumably smaller than the last 1447 * and move the last entry back one. 1448 */ 1449 bp--; 1450 printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 1451 (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 1452 bp[-1] = bp[0]; 1453 bp[0].m_size = bp[0].m_addr = 0; 1454 } 1455 done: 1456 return; 1457 badrmfree: 1458 printf("bad rmfree\n"); 1459 } 1460 1461 #include <varargs.h> 1462 1463 error(va_alist) 1464 va_dcl 1465 { 1466 char *fmt; 1467 va_list ap; 1468 extern errno; 1469 1470 fprintf(stderr, "%s: ", Program); 1471 va_start(ap); 1472 fmt = va_arg(ap, char *); 1473 (void) vfprintf(stderr, fmt, ap); 1474 va_end(ap); 1475 fprintf(stderr, "\n"); 1476 } 1477 1478 syserror(va_alist) 1479 va_dcl 1480 { 1481 char *fmt; 1482 va_list ap; 1483 extern errno; 1484 1485 fprintf(stderr, "%s: ", Program); 1486 va_start(ap); 1487 fmt = va_arg(ap, char *); 1488 (void) vfprintf(stderr, fmt, ap); 1489 va_end(ap); 1490 fprintf(stderr, ": %s\n", strerror(errno)); 1491 } 1492