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