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