1 /*- 2 * Copyright (c) 1980, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1980, 1991, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)pstat.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/time.h> 20 #include <sys/vnode.h> 21 #include <sys/map.h> 22 #define KERNEL 23 #include <sys/file.h> 24 #include <ufs/ufs/quota.h> 25 #include <ufs/ufs/inode.h> 26 #undef KERNEL 27 #define NFS 28 #include <sys/mount.h> 29 #undef NFS 30 #include <sys/stat.h> 31 #include <nfs/nfsnode.h> 32 #include <sys/ioctl.h> 33 #include <sys/tty.h> 34 #include <sys/conf.h> 35 36 #include <sys/sysctl.h> 37 38 #include <err.h> 39 #include <kvm.h> 40 #include <limits.h> 41 #include <nlist.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "pathnames.h" 48 49 struct nlist nl[] = { 50 #define VM_SWAPMAP 0 51 { "_swapmap" }, /* list of free swap areas */ 52 #define VM_NSWAPMAP 1 53 { "_nswapmap" },/* size of the swap map */ 54 #define VM_SWDEVT 2 55 { "_swdevt" }, /* list of swap devices and sizes */ 56 #define VM_NSWAP 3 57 { "_nswap" }, /* size of largest swap device */ 58 #define VM_NSWDEV 4 59 { "_nswdev" }, /* number of swap devices */ 60 #define VM_DMMAX 5 61 { "_dmmax" }, /* maximum size of a swap block */ 62 #define V_NUMV 6 63 { "_numvnodes" }, 64 #define V_ROOTFS 7 65 { "_rootfs" }, 66 #define FNL_NFILE 8 67 {"_nfiles"}, 68 #define FNL_MAXFILE 9 69 {"_maxfiles"}, 70 #define NLMANDATORY FNL_MAXFILE /* names up to here are mandatory */ 71 #define SCONS NLMANDATORY + 1 72 { "_cons" }, 73 #define SPTY NLMANDATORY + 2 74 { "_pt_tty" }, 75 #define SNPTY NLMANDATORY + 3 76 { "_npty" }, 77 78 #ifdef hp300 79 #define SDCA (SNPTY+1) 80 { "_dca_tty" }, 81 #define SNDCA (SNPTY+2) 82 { "_ndca" }, 83 #define SDCM (SNPTY+3) 84 { "_dcm_tty" }, 85 #define SNDCM (SNPTY+4) 86 { "_ndcm" }, 87 #define SDCL (SNPTY+5) 88 { "_dcl_tty" }, 89 #define SNDCL (SNPTY+6) 90 { "_ndcl" }, 91 #define SITE (SNPTY+7) 92 { "_ite_tty" }, 93 #define SNITE (SNPTY+8) 94 { "_nite" }, 95 #endif 96 97 #ifdef mips 98 #define SDC (SNPTY+1) 99 { "_dc_tty" }, 100 #define SNDC (SNPTY+2) 101 { "_dc_cnt" }, 102 #endif 103 104 { "" } 105 }; 106 107 int usenumflag; 108 int totalflag; 109 char *nlistf = NULL; 110 char *memf = NULL; 111 kvm_t *kd; 112 113 #define SVAR(var) __STRING(var) /* to force expansion */ 114 #define KGET(idx, var) \ 115 KGET1(idx, &var, sizeof(var), SVAR(var)) 116 #define KGET1(idx, p, s, msg) \ 117 KGET2(nl[idx].n_value, p, s, msg) 118 #define KGET2(addr, p, s, msg) \ 119 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 120 warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 121 #define KGETRET(addr, p, s, msg) \ 122 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 123 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 124 return (0); \ 125 } 126 127 void filemode __P((void)); 128 int getfiles __P((char **, int *)); 129 struct mount * 130 getmnt __P((struct mount *)); 131 struct e_vnode * 132 kinfo_vnodes __P((int *)); 133 struct e_vnode * 134 loadvnodes __P((int *)); 135 void mount_print __P((struct mount *)); 136 void nfs_header __P((void)); 137 int nfs_print __P((struct vnode *)); 138 void swapmode __P((void)); 139 void ttymode __P((void)); 140 void ttyprt __P((struct tty *, int)); 141 void ttytype __P((struct tty *, char *, int, int)); 142 void ufs_header __P((void)); 143 int ufs_print __P((struct vnode *)); 144 void usage __P((void)); 145 void vnode_header __P((void)); 146 void vnode_print __P((struct vnode *, struct vnode *)); 147 void vnodemode __P((void)); 148 149 int 150 main(argc, argv) 151 int argc; 152 char *argv[]; 153 { 154 extern char *optarg; 155 extern int optind; 156 int ch, i, quit, ret; 157 int fileflag, swapflag, ttyflag, vnodeflag; 158 char buf[_POSIX2_LINE_MAX]; 159 160 fileflag = swapflag = ttyflag = vnodeflag = 0; 161 while ((ch = getopt(argc, argv, "TM:N:finstv")) != EOF) 162 switch (ch) { 163 case 'f': 164 fileflag = 1; 165 break; 166 case 'M': 167 memf = optarg; 168 break; 169 case 'N': 170 nlistf = optarg; 171 break; 172 case 'n': 173 usenumflag = 1; 174 break; 175 case 's': 176 swapflag = 1; 177 break; 178 case 'T': 179 totalflag = 1; 180 break; 181 case 't': 182 ttyflag = 1; 183 break; 184 case 'v': 185 case 'i': /* Backward compatibility. */ 186 vnodeflag = 1; 187 break; 188 default: 189 usage(); 190 } 191 argc -= optind; 192 argv += optind; 193 194 /* 195 * Discard setgid privileges if not the running kernel so that bad 196 * guys can't print interesting stuff from kernel memory. 197 */ 198 if (nlistf != NULL || memf != NULL) 199 (void)setgid(getgid()); 200 201 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 202 errx(1, "kvm_openfiles: %s", buf); 203 if ((ret = kvm_nlist(kd, nl)) != 0) { 204 if (ret == -1) 205 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 206 for (i = quit = 0; i <= NLMANDATORY; i++) 207 if (!nl[i].n_value) { 208 quit = 1; 209 warnx("undefined symbol: %s\n", nl[i].n_name); 210 } 211 if (quit) 212 exit(1); 213 } 214 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) 215 usage(); 216 if (fileflag || totalflag) 217 filemode(); 218 if (vnodeflag || totalflag) 219 vnodemode(); 220 if (ttyflag) 221 ttymode(); 222 if (swapflag || totalflag) 223 swapmode(); 224 exit (0); 225 } 226 227 struct e_vnode { 228 struct vnode *avnode; 229 struct vnode vnode; 230 }; 231 232 void 233 vnodemode() 234 { 235 register struct e_vnode *e_vnodebase, *endvnode, *evp; 236 register struct vnode *vp; 237 register struct mount *maddr, *mp; 238 int numvnodes; 239 240 e_vnodebase = loadvnodes(&numvnodes); 241 if (totalflag) { 242 (void)printf("%7d vnodes\n", numvnodes); 243 return; 244 } 245 endvnode = e_vnodebase + numvnodes; 246 (void)printf("%d active vnodes\n", numvnodes); 247 248 249 #define ST mp->mnt_stat 250 maddr = NULL; 251 for (evp = e_vnodebase; evp < endvnode; evp++) { 252 vp = &evp->vnode; 253 if (vp->v_mount != maddr) { 254 /* 255 * New filesystem 256 */ 257 if ((mp = getmnt(vp->v_mount)) == NULL) 258 continue; 259 maddr = vp->v_mount; 260 mount_print(mp); 261 vnode_header(); 262 switch(ST.f_type) { 263 case MOUNT_UFS: 264 case MOUNT_MFS: 265 ufs_header(); 266 break; 267 case MOUNT_NFS: 268 nfs_header(); 269 break; 270 case MOUNT_NONE: 271 case MOUNT_PC: 272 default: 273 break; 274 } 275 (void)printf("\n"); 276 } 277 vnode_print(evp->avnode, vp); 278 switch(ST.f_type) { 279 case MOUNT_UFS: 280 case MOUNT_MFS: 281 ufs_print(vp); 282 break; 283 case MOUNT_NFS: 284 nfs_print(vp); 285 break; 286 case MOUNT_NONE: 287 case MOUNT_PC: 288 default: 289 break; 290 } 291 (void)printf("\n"); 292 } 293 free(e_vnodebase); 294 } 295 296 void 297 vnode_header() 298 { 299 (void)printf("ADDR TYP VFLAG USE HOLD"); 300 } 301 302 void 303 vnode_print(avnode, vp) 304 struct vnode *avnode; 305 struct vnode *vp; 306 { 307 char *type, flags[16]; 308 char *fp = flags; 309 register int flag; 310 311 /* 312 * set type 313 */ 314 switch(vp->v_type) { 315 case VNON: 316 type = "non"; break; 317 case VREG: 318 type = "reg"; break; 319 case VDIR: 320 type = "dir"; break; 321 case VBLK: 322 type = "blk"; break; 323 case VCHR: 324 type = "chr"; break; 325 case VLNK: 326 type = "lnk"; break; 327 case VSOCK: 328 type = "soc"; break; 329 case VFIFO: 330 type = "fif"; break; 331 case VBAD: 332 type = "bad"; break; 333 default: 334 type = "unk"; break; 335 } 336 /* 337 * gather flags 338 */ 339 flag = vp->v_flag; 340 if (flag & VROOT) 341 *fp++ = 'R'; 342 if (flag & VTEXT) 343 *fp++ = 'T'; 344 if (flag & VSYSTEM) 345 *fp++ = 'S'; 346 if (flag & VXLOCK) 347 *fp++ = 'L'; 348 if (flag & VXWANT) 349 *fp++ = 'W'; 350 if (flag & VBWAIT) 351 *fp++ = 'B'; 352 if (flag & VALIASED) 353 *fp++ = 'A'; 354 if (flag == 0) 355 *fp++ = '-'; 356 *fp = '\0'; 357 (void)printf("%8x %s %5s %4d %4d", 358 avnode, type, flags, vp->v_usecount, vp->v_holdcnt); 359 } 360 361 void 362 ufs_header() 363 { 364 (void)printf(" FILEID IFLAG RDEV|SZ"); 365 } 366 367 int 368 ufs_print(vp) 369 struct vnode *vp; 370 { 371 register int flag; 372 struct inode inode, *ip = &inode; 373 char flagbuf[16], *flags = flagbuf; 374 char *name; 375 mode_t type; 376 377 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 378 flag = ip->i_flag; 379 if (flag & ILOCKED) 380 *flags++ = 'L'; 381 if (flag & IWANT) 382 *flags++ = 'W'; 383 if (flag & IRENAME) 384 *flags++ = 'R'; 385 if (flag & IUPD) 386 *flags++ = 'U'; 387 if (flag & IACC) 388 *flags++ = 'A'; 389 if (flag & ICHG) 390 *flags++ = 'C'; 391 if (flag & IMOD) 392 *flags++ = 'M'; 393 if (flag & ISHLOCK) 394 *flags++ = 'S'; 395 if (flag & IEXLOCK) 396 *flags++ = 'E'; 397 if (flag & ILWAIT) 398 *flags++ = 'Z'; 399 if (flag == 0) 400 *flags++ = '-'; 401 *flags = '\0'; 402 403 (void)printf(" %6d %5s", ip->i_number, flagbuf); 404 type = ip->i_mode & S_IFMT; 405 if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) 406 if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL)) 407 (void)printf(" %2d,%-2d", 408 major(ip->i_rdev), minor(ip->i_rdev)); 409 else 410 (void)printf(" %7s", name); 411 else 412 (void)printf(" %7qd", ip->i_size); 413 return (0); 414 } 415 416 void 417 nfs_header() 418 { 419 (void)printf(" FILEID NFLAG RDEV|SZ"); 420 } 421 422 int 423 nfs_print(vp) 424 struct vnode *vp; 425 { 426 struct nfsnode nfsnode, *np = &nfsnode; 427 char flagbuf[16], *flags = flagbuf; 428 register int flag; 429 char *name; 430 mode_t type; 431 432 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); 433 flag = np->n_flag; 434 if (flag & NFLUSHWANT) 435 *flags++ = 'W'; 436 if (flag & NFLUSHINPROG) 437 *flags++ = 'P'; 438 if (flag & NMODIFIED) 439 *flags++ = 'M'; 440 if (flag & NWRITEERR) 441 *flags++ = 'E'; 442 if (flag & NQNFSNONCACHE) 443 *flags++ = 'X'; 444 if (flag & NQNFSWRITE) 445 *flags++ = 'O'; 446 if (flag & NQNFSEVICTED) 447 *flags++ = 'G'; 448 if (flag == 0) 449 *flags++ = '-'; 450 *flags = '\0'; 451 452 #define VT np->n_vattr 453 (void)printf(" %6d %5s", VT.va_fileid, flagbuf); 454 type = VT.va_mode & S_IFMT; 455 if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode)) 456 if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL)) 457 (void)printf(" %2d,%-2d", 458 major(VT.va_rdev), minor(VT.va_rdev)); 459 else 460 (void)printf(" %7s", name); 461 else 462 (void)printf(" %7qd", np->n_size); 463 return (0); 464 } 465 466 /* 467 * Given a pointer to a mount structure in kernel space, 468 * read it in and return a usable pointer to it. 469 */ 470 struct mount * 471 getmnt(maddr) 472 struct mount *maddr; 473 { 474 static struct mtab { 475 struct mtab *next; 476 struct mount *maddr; 477 struct mount mount; 478 } *mhead = NULL; 479 register struct mtab *mt; 480 481 for (mt = mhead; mt != NULL; mt = mt->next) 482 if (maddr == mt->maddr) 483 return (&mt->mount); 484 if ((mt = malloc(sizeof(struct mtab))) == NULL) 485 err(1, NULL); 486 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); 487 mt->maddr = maddr; 488 mt->next = mhead; 489 mhead = mt; 490 return (&mt->mount); 491 } 492 493 void 494 mount_print(mp) 495 struct mount *mp; 496 { 497 register int flags; 498 char *type; 499 500 #define ST mp->mnt_stat 501 (void)printf("*** MOUNT "); 502 switch (ST.f_type) { 503 case MOUNT_NONE: 504 type = "none"; 505 break; 506 case MOUNT_UFS: 507 type = "ufs"; 508 break; 509 case MOUNT_NFS: 510 type = "nfs"; 511 break; 512 case MOUNT_MFS: 513 type = "mfs"; 514 break; 515 case MOUNT_PC: 516 type = "pc"; 517 break; 518 default: 519 type = "unknown"; 520 break; 521 } 522 (void)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 (void)printf("%srdonly", comma); 530 flags &= ~MNT_RDONLY; 531 comma = ","; 532 } 533 if (flags & MNT_SYNCHRONOUS) { 534 (void)printf("%ssynchronous", comma); 535 flags &= ~MNT_SYNCHRONOUS; 536 comma = ","; 537 } 538 if (flags & MNT_NOEXEC) { 539 (void)printf("%snoexec", comma); 540 flags &= ~MNT_NOEXEC; 541 comma = ","; 542 } 543 if (flags & MNT_NOSUID) { 544 (void)printf("%snosuid", comma); 545 flags &= ~MNT_NOSUID; 546 comma = ","; 547 } 548 if (flags & MNT_NODEV) { 549 (void)printf("%snodev", comma); 550 flags &= ~MNT_NODEV; 551 comma = ","; 552 } 553 if (flags & MNT_EXPORTED) { 554 (void)printf("%sexport", comma); 555 flags &= ~MNT_EXPORTED; 556 comma = ","; 557 } 558 if (flags & MNT_EXRDONLY) { 559 (void)printf("%sexrdonly", comma); 560 flags &= ~MNT_EXRDONLY; 561 comma = ","; 562 } 563 if (flags & MNT_LOCAL) { 564 (void)printf("%slocal", comma); 565 flags &= ~MNT_LOCAL; 566 comma = ","; 567 } 568 if (flags & MNT_QUOTA) { 569 (void)printf("%squota", comma); 570 flags &= ~MNT_QUOTA; 571 comma = ","; 572 } 573 /* filesystem control flags */ 574 if (flags & MNT_UPDATE) { 575 (void)printf("%supdate", comma); 576 flags &= ~MNT_UPDATE; 577 comma = ","; 578 } 579 if (flags & MNT_MLOCK) { 580 (void)printf("%slock", comma); 581 flags &= ~MNT_MLOCK; 582 comma = ","; 583 } 584 if (flags & MNT_MWAIT) { 585 (void)printf("%swait", comma); 586 flags &= ~MNT_MWAIT; 587 comma = ","; 588 } 589 if (flags & MNT_MPBUSY) { 590 (void)printf("%sbusy", comma); 591 flags &= ~MNT_MPBUSY; 592 comma = ","; 593 } 594 if (flags & MNT_MPWANT) { 595 (void)printf("%swant", comma); 596 flags &= ~MNT_MPWANT; 597 comma = ","; 598 } 599 if (flags & MNT_UNMOUNT) { 600 (void)printf("%sunmount", comma); 601 flags &= ~MNT_UNMOUNT; 602 comma = ","; 603 } 604 if (flags) 605 (void)printf("%sunknown_flags:%x", comma, flags); 606 (void)printf(")"); 607 } 608 (void)printf("\n"); 609 #undef ST 610 } 611 612 struct e_vnode * 613 loadvnodes(avnodes) 614 int *avnodes; 615 { 616 int mib[2]; 617 size_t copysize; 618 struct e_vnode *vnodebase; 619 620 if (memf != NULL) { 621 /* 622 * do it by hand 623 */ 624 return (kinfo_vnodes(avnodes)); 625 } 626 mib[0] = CTL_KERN; 627 mib[1] = KERN_VNODE; 628 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) 629 err(1, "sysctl: KERN_VNODE"); 630 if ((vnodebase = malloc(copysize)) == NULL) 631 err(1, NULL); 632 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) 633 err(1, "sysctl: KERN_VNODE"); 634 if (copysize % sizeof(struct e_vnode)) 635 errx(1, "vnode size mismatch"); 636 *avnodes = copysize / sizeof(struct e_vnode); 637 638 return (vnodebase); 639 } 640 641 /* 642 * simulate what a running kernel does in in kinfo_vnode 643 */ 644 struct e_vnode * 645 kinfo_vnodes(avnodes) 646 int *avnodes; 647 { 648 int numvnodes; 649 struct mount *rootfs, *mp, mount; 650 char *vbuf, *evbuf, *bp; 651 struct vnode *vp, vnode; 652 int num; 653 654 #define VPTRSZ sizeof(struct vnode *) 655 #define VNODESZ sizeof(struct vnode) 656 657 KGET(V_NUMV, numvnodes); 658 if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL) 659 err(1, NULL); 660 bp = vbuf; 661 evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ); 662 KGET(V_ROOTFS, rootfs); 663 mp = rootfs; 664 do { 665 KGET2(mp, &mount, sizeof(mount), "mount entry"); 666 for (vp = mount.mnt_mounth; vp; vp = vnode.v_mountf) { 667 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 668 if ((bp + VPTRSZ + VNODESZ) > evbuf) 669 /* XXX - should realloc */ 670 errx(1, "no more room for vnodes"); 671 memmove(bp, &vp, VPTRSZ); 672 bp += VPTRSZ; 673 memmove(bp, &vnode, VNODESZ); 674 bp += VNODESZ; 675 num++; 676 } 677 mp = mount.mnt_next; 678 } while (mp != rootfs); 679 *avnodes = num; 680 return ((struct e_vnode *)vbuf); 681 } 682 683 char hdr[]=" LINE RAW CAN OUT HWT LWT ADDR COL STATE SESS PGID DISC\n"; 684 int ttyspace = 128; 685 686 void 687 ttymode() 688 { 689 struct tty *tty; 690 691 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL) 692 err(1, NULL); 693 #ifndef hp300 694 (void)printf("1 console\n"); 695 KGET(SCONS, *tty); 696 (void)printf(hdr); 697 ttyprt(&tty[0], 0); 698 #endif 699 #ifdef vax 700 if (nl[SNQD].n_type != 0) 701 qdss(); 702 if (nl[SNDZ].n_type != 0) 703 ttytype(tty, "dz", SDZ, SNDZ); 704 if (nl[SNDH].n_type != 0) 705 ttytype(tty, "dh", SDH, SNDH); 706 if (nl[SNDMF].n_type != 0) 707 ttytype(tty, "dmf", SDMF, SNDMF); 708 if (nl[SNDHU].n_type != 0) 709 ttytype(tty, "dhu", SDHU, SNDHU); 710 if (nl[SNDMZ].n_type != 0) 711 ttytype(tty, "dmz", SDMZ, SNDMZ); 712 #endif 713 #ifdef tahoe 714 if (nl[SNVX].n_type != 0) 715 ttytype(tty, "vx", SVX, SNVX); 716 if (nl[SNMP].n_type != 0) 717 ttytype(tty, "mp", SMP, SNMP); 718 #endif 719 #ifdef hp300 720 if (nl[SNITE].n_type != 0) 721 ttytype(tty, "ite", SITE, SNITE); 722 if (nl[SNDCA].n_type != 0) 723 ttytype(tty, "dca", SDCA, SNDCA); 724 if (nl[SNDCM].n_type != 0) 725 ttytype(tty, "dcm", SDCM, SNDCM); 726 if (nl[SNDCL].n_type != 0) 727 ttytype(tty, "dcl", SDCL, SNDCL); 728 #endif 729 #ifdef mips 730 if (nl[SNDC].n_type != 0) 731 ttytype(tty, "dc", SDC, SNDC); 732 #endif 733 if (nl[SNPTY].n_type != 0) 734 ttytype(tty, "pty", SPTY, SNPTY); 735 } 736 737 void 738 ttytype(tty, name, type, number) 739 register struct tty *tty; 740 char *name; 741 int type, number; 742 { 743 register struct tty *tp; 744 int ntty; 745 746 if (tty == NULL) 747 return; 748 KGET(number, ntty); 749 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines"); 750 if (ntty > ttyspace) { 751 ttyspace = ntty; 752 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0) 753 err(1, NULL); 754 } 755 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs"); 756 (void)printf(hdr); 757 for (tp = tty; tp < &tty[ntty]; tp++) 758 ttyprt(tp, tp - tty); 759 } 760 761 struct { 762 int flag; 763 char val; 764 } ttystates[] = { 765 { TS_WOPEN, 'W'}, 766 { TS_ISOPEN, 'O'}, 767 { TS_CARR_ON, 'C'}, 768 { TS_TIMEOUT, 'T'}, 769 { TS_FLUSH, 'F'}, 770 { TS_BUSY, 'B'}, 771 { TS_ASLEEP, 'A'}, 772 { TS_XCLUDE, 'X'}, 773 { TS_TTSTOP, 'S'}, 774 { TS_TBLOCK, 'K'}, 775 { TS_ASYNC, 'Y'}, 776 { TS_BKSL, 'D'}, 777 { TS_ERASE, 'E'}, 778 { TS_LNCH, 'L'}, 779 { TS_TYPEN, 'P'}, 780 { TS_CNTTB, 'N'}, 781 { 0, '\0'}, 782 }; 783 784 void 785 ttyprt(tp, line) 786 register struct tty *tp; 787 int line; 788 { 789 register int i, j; 790 pid_t pgid; 791 char *name, state[20]; 792 793 if (usenumflag || tp->t_dev == 0 || 794 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 795 (void)printf("%7d ", line); 796 else 797 (void)printf("%7s ", name); 798 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 799 (void)printf("%3d %4d %3d %8x %3d ", tp->t_outq.c_cc, 800 tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col); 801 for (i = j = 0; ttystates[i].flag; i++) 802 if (tp->t_state&ttystates[i].flag) 803 state[j++] = ttystates[i].val; 804 if (j == 0) 805 state[j++] = '-'; 806 state[j] = '\0'; 807 (void)printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE); 808 pgid = 0; 809 if (tp->t_pgrp != NULL) 810 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); 811 (void)printf("%6d ", pgid); 812 switch (tp->t_line) { 813 case TTYDISC: 814 (void)printf("term\n"); 815 break; 816 case TABLDISC: 817 (void)printf("tab\n"); 818 break; 819 case SLIPDISC: 820 (void)printf("slip\n"); 821 break; 822 default: 823 (void)printf("%d\n", tp->t_line); 824 break; 825 } 826 } 827 828 void 829 filemode() 830 { 831 register struct file *fp; 832 struct file *addr; 833 char *buf, flagbuf[16], *fbp; 834 int len, maxfile, nfile; 835 static char *dtypes[] = { "???", "inode", "socket" }; 836 837 KGET(FNL_MAXFILE, maxfile); 838 if (totalflag) { 839 KGET(FNL_NFILE, nfile); 840 (void)printf("%3d/%3d files\n", nfile, maxfile); 841 return; 842 } 843 if (getfiles(&buf, &len) == -1) 844 return; 845 /* 846 * Getfiles returns in malloc'd memory a pointer to the first file 847 * structure, and then an array of file structs (whose addresses are 848 * derivable from the previous entry). 849 */ 850 addr = *((struct file **)buf); 851 fp = (struct file *)(buf + sizeof(struct file *)); 852 nfile = (len - sizeof(struct file *)) / sizeof(struct file); 853 854 (void)printf("%d/%d open files\n", nfile, maxfile); 855 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 856 for (; (char *)fp < buf + len; addr = fp->f_filef, fp++) { 857 if ((unsigned)fp->f_type > DTYPE_SOCKET) 858 continue; 859 (void)printf("%x ", addr); 860 (void)printf("%-8.8s", dtypes[fp->f_type]); 861 fbp = flagbuf; 862 if (fp->f_flag & FREAD) 863 *fbp++ = 'R'; 864 if (fp->f_flag & FWRITE) 865 *fbp++ = 'W'; 866 if (fp->f_flag & FAPPEND) 867 *fbp++ = 'A'; 868 #ifdef FSHLOCK /* currently gone */ 869 if (fp->f_flag & FSHLOCK) 870 *fbp++ = 'S'; 871 if (fp->f_flag & FEXLOCK) 872 *fbp++ = 'X'; 873 #endif 874 if (fp->f_flag & FASYNC) 875 *fbp++ = 'I'; 876 *fbp = '\0'; 877 (void)printf("%6s %3d", flagbuf, fp->f_count); 878 (void)printf(" %3d", fp->f_msgcount); 879 (void)printf(" %8.1x", fp->f_data); 880 if (fp->f_offset < 0) 881 (void)printf(" %qx\n", fp->f_offset); 882 else 883 (void)printf(" %qd\n", fp->f_offset); 884 } 885 free(buf); 886 } 887 888 int 889 getfiles(abuf, alen) 890 char **abuf; 891 int *alen; 892 { 893 size_t len; 894 int mib[2]; 895 char *buf; 896 897 /* 898 * XXX 899 * Add emulation of KINFO_FILE here. 900 */ 901 if (memf != NULL) 902 errx(1, "files on dead kernel, not implemented\n"); 903 904 mib[0] = CTL_KERN; 905 mib[1] = KERN_FILE; 906 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 907 warn("sysctl: KERN_FILE"); 908 return (-1); 909 } 910 if ((buf = malloc(len)) == NULL) 911 err(1, NULL); 912 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 913 warn("sysctl: KERN_FILE"); 914 return (-1); 915 } 916 *abuf = buf; 917 *alen = len; 918 return (0); 919 } 920 921 /* 922 * swapmode is based on a program called swapinfo written 923 * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 924 */ 925 void 926 swapmode() 927 { 928 char *header; 929 int hlen, nswap, nswdev, dmmax, nswapmap; 930 int s, e, div, i, avail, nfree, npfree, used; 931 struct swdevt *sw; 932 long blocksize, *perdev; 933 struct map *swapmap, *kswapmap; 934 struct mapent *mp; 935 936 KGET(VM_NSWAP, nswap); 937 KGET(VM_NSWDEV, nswdev); 938 KGET(VM_DMMAX, dmmax); 939 KGET(VM_NSWAPMAP, nswapmap); 940 KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */ 941 if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || 942 (perdev = malloc(nswdev * sizeof(*perdev))) == NULL || 943 (mp = malloc(nswapmap * sizeof(*mp))) == NULL) 944 err(1, "malloc"); 945 KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt"); 946 KGET2((long)kswapmap, mp, nswapmap * sizeof(*mp), "swapmap"); 947 948 /* First entry in map is `struct map'; rest are mapent's. */ 949 swapmap = (struct map *)mp; 950 if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap) 951 errx(1, "panic: nswapmap goof"); 952 953 /* Count up swap space. */ 954 nfree = 0; 955 memset(perdev, 0, nswdev * sizeof(*perdev)); 956 for (mp++; mp->m_addr != 0; mp++) { 957 s = mp->m_addr; /* start of swap region */ 958 e = mp->m_addr + mp->m_size; /* end of region */ 959 nfree += mp->m_size; 960 961 /* 962 * Swap space is split up among the configured disks. 963 * The first dmmax blocks of swap space some from the 964 * first disk, the next dmmax blocks from the next, 965 * and so on. The list of free space joins adjacent 966 * free blocks, ignoring device boundries. If we want 967 * to keep track of this information per device, we'll 968 * just have to extract it ourselves. 969 */ 970 971 /* calculate first device on which this falls */ 972 i = (s / dmmax) % nswdev; 973 while (s < e) { /* XXX this is inefficient */ 974 int bound = roundup(s+1, dmmax); 975 976 if (bound > e) 977 bound = e; 978 perdev[i] += bound - s; 979 if (++i >= nswdev) 980 i = 0; 981 s = bound; 982 } 983 } 984 985 header = getbsize(&hlen, &blocksize); 986 if (!totalflag) 987 (void)printf("%-10s %*s %10s %10s %10s\n", 988 "Device", hlen, header, "Used", "Available", "Capacity"); 989 div = blocksize / 512; 990 avail = npfree = 0; 991 for (i = 0; i < nswdev; i++) { 992 int xsize, xfree; 993 994 if (!totalflag) 995 (void)printf("/dev/%-5s %*d ", 996 devname(sw[i].sw_dev, S_IFBLK), 997 hlen, sw[i].sw_nblks / div); 998 999 /* 1000 * Don't report statistics for partitions which have not 1001 * yet been activated via swapon(8). 1002 */ 1003 if (!sw[i].sw_freed) { 1004 if (totalflag) 1005 continue; 1006 (void)printf(" *** not available for swapping ***\n"); 1007 continue; 1008 } 1009 xsize = sw[i].sw_nblks; 1010 xfree = perdev[i]; 1011 used = xsize - xfree; 1012 npfree++; 1013 avail += xsize; 1014 if (totalflag) 1015 continue; 1016 (void)printf("%10d %10d %7.0f%%\n", 1017 used / div, xfree / div, 1018 (double)used / (double)xsize * 100.0); 1019 } 1020 1021 /* 1022 * If only one partition has been set up via swapon(8), we don't 1023 * need to bother with totals. 1024 */ 1025 used = avail - nfree; 1026 if (totalflag) { 1027 (void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048); 1028 return; 1029 } 1030 if (npfree > 1) { 1031 (void)printf("%-10s %*d %10d %10d %7.0f%%\n", 1032 "Total", hlen, avail / div, used / div, nfree / div, 1033 (double)used / (double)avail * 100.0); 1034 } 1035 } 1036 1037 void 1038 usage() 1039 { 1040 (void)fprintf(stderr, 1041 "usage: pstat -Tfnstv [system] [-M core] [-N system]\n"); 1042 exit(1); 1043 } 1044