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