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.9 (Berkeley) 02/16/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 (num = 0, mp = mountlist.tqh_first; 667 mp != NULL; mp = mp->mnt_list.tqe_next) { 668 KGET2(mp, &mount, sizeof(mount), "mount entry"); 669 for (vp = mount.mnt_vnodelist.lh_first; 670 vp != NULL; vp = vp->v_mntvnodes.le_next) { 671 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 672 if ((bp + VPTRSZ + VNODESZ) > evbuf) 673 /* XXX - should realloc */ 674 errx(1, "no more room for vnodes"); 675 memmove(bp, &vp, VPTRSZ); 676 bp += VPTRSZ; 677 memmove(bp, &vnode, VNODESZ); 678 bp += VNODESZ; 679 num++; 680 } 681 } 682 *avnodes = num; 683 return ((struct e_vnode *)vbuf); 684 } 685 686 char hdr[]=" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n"; 687 int ttyspace = 128; 688 689 void 690 ttymode() 691 { 692 struct tty *tty; 693 694 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL) 695 err(1, NULL); 696 #ifndef hp300 697 (void)printf("1 console\n"); 698 KGET(SCONS, *tty); 699 (void)printf(hdr); 700 ttyprt(&tty[0], 0); 701 #endif 702 #ifdef vax 703 if (nl[SNQD].n_type != 0) 704 qdss(); 705 if (nl[SNDZ].n_type != 0) 706 ttytype(tty, "dz", SDZ, SNDZ); 707 if (nl[SNDH].n_type != 0) 708 ttytype(tty, "dh", SDH, SNDH); 709 if (nl[SNDMF].n_type != 0) 710 ttytype(tty, "dmf", SDMF, SNDMF); 711 if (nl[SNDHU].n_type != 0) 712 ttytype(tty, "dhu", SDHU, SNDHU); 713 if (nl[SNDMZ].n_type != 0) 714 ttytype(tty, "dmz", SDMZ, SNDMZ); 715 #endif 716 #ifdef tahoe 717 if (nl[SNVX].n_type != 0) 718 ttytype(tty, "vx", SVX, SNVX); 719 if (nl[SNMP].n_type != 0) 720 ttytype(tty, "mp", SMP, SNMP); 721 #endif 722 #ifdef hp300 723 if (nl[SNITE].n_type != 0) 724 ttytype(tty, "ite", SITE, SNITE); 725 if (nl[SNDCA].n_type != 0) 726 ttytype(tty, "dca", SDCA, SNDCA); 727 if (nl[SNDCM].n_type != 0) 728 ttytype(tty, "dcm", SDCM, SNDCM); 729 if (nl[SNDCL].n_type != 0) 730 ttytype(tty, "dcl", SDCL, SNDCL); 731 #endif 732 #ifdef mips 733 if (nl[SNDC].n_type != 0) 734 ttytype(tty, "dc", SDC, SNDC); 735 #endif 736 if (nl[SNPTY].n_type != 0) 737 ttytype(tty, "pty", SPTY, SNPTY); 738 } 739 740 void 741 ttytype(tty, name, type, number) 742 register struct tty *tty; 743 char *name; 744 int type, number; 745 { 746 register struct tty *tp; 747 int ntty; 748 749 if (tty == NULL) 750 return; 751 KGET(number, ntty); 752 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines"); 753 if (ntty > ttyspace) { 754 ttyspace = ntty; 755 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0) 756 err(1, NULL); 757 } 758 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs"); 759 (void)printf(hdr); 760 for (tp = tty; tp < &tty[ntty]; tp++) 761 ttyprt(tp, tp - tty); 762 } 763 764 struct { 765 int flag; 766 char val; 767 } ttystates[] = { 768 { TS_WOPEN, 'W'}, 769 { TS_ISOPEN, 'O'}, 770 { TS_CARR_ON, 'C'}, 771 { TS_TIMEOUT, 'T'}, 772 { TS_FLUSH, 'F'}, 773 { TS_BUSY, 'B'}, 774 { TS_ASLEEP, 'A'}, 775 { TS_XCLUDE, 'X'}, 776 { TS_TTSTOP, 'S'}, 777 { TS_TBLOCK, 'K'}, 778 { TS_ASYNC, 'Y'}, 779 { TS_BKSL, 'D'}, 780 { TS_ERASE, 'E'}, 781 { TS_LNCH, 'L'}, 782 { TS_TYPEN, 'P'}, 783 { TS_CNTTB, 'N'}, 784 { 0, '\0'}, 785 }; 786 787 void 788 ttyprt(tp, line) 789 register struct tty *tp; 790 int line; 791 { 792 register int i, j; 793 pid_t pgid; 794 char *name, state[20]; 795 796 if (usenumflag || tp->t_dev == 0 || 797 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 798 (void)printf("%7d ", line); 799 else 800 (void)printf("%7s ", name); 801 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 802 (void)printf("%3d %4d %3d %3d ", tp->t_outq.c_cc, 803 tp->t_hiwat, tp->t_lowat, tp->t_column); 804 for (i = j = 0; ttystates[i].flag; i++) 805 if (tp->t_state&ttystates[i].flag) 806 state[j++] = ttystates[i].val; 807 if (j == 0) 808 state[j++] = '-'; 809 state[j] = '\0'; 810 (void)printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE); 811 pgid = 0; 812 if (tp->t_pgrp != NULL) 813 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); 814 (void)printf("%6d ", pgid); 815 switch (tp->t_line) { 816 case TTYDISC: 817 (void)printf("term\n"); 818 break; 819 case TABLDISC: 820 (void)printf("tab\n"); 821 break; 822 case SLIPDISC: 823 (void)printf("slip\n"); 824 break; 825 default: 826 (void)printf("%d\n", tp->t_line); 827 break; 828 } 829 } 830 831 void 832 filemode() 833 { 834 register struct file *fp; 835 struct file *addr; 836 char *buf, flagbuf[16], *fbp; 837 int len, maxfile, nfile; 838 static char *dtypes[] = { "???", "inode", "socket" }; 839 840 KGET(FNL_MAXFILE, maxfile); 841 if (totalflag) { 842 KGET(FNL_NFILE, nfile); 843 (void)printf("%3d/%3d files\n", nfile, maxfile); 844 return; 845 } 846 if (getfiles(&buf, &len) == -1) 847 return; 848 /* 849 * Getfiles returns in malloc'd memory a pointer to the first file 850 * structure, and then an array of file structs (whose addresses are 851 * derivable from the previous entry). 852 */ 853 addr = *((struct file **)buf); 854 fp = (struct file *)(buf + sizeof(struct file *)); 855 nfile = (len - sizeof(struct file *)) / sizeof(struct file); 856 857 (void)printf("%d/%d open files\n", nfile, maxfile); 858 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 859 for (; (char *)fp < buf + len; addr = fp->f_filef, fp++) { 860 if ((unsigned)fp->f_type > DTYPE_SOCKET) 861 continue; 862 (void)printf("%x ", addr); 863 (void)printf("%-8.8s", dtypes[fp->f_type]); 864 fbp = flagbuf; 865 if (fp->f_flag & FREAD) 866 *fbp++ = 'R'; 867 if (fp->f_flag & FWRITE) 868 *fbp++ = 'W'; 869 if (fp->f_flag & FAPPEND) 870 *fbp++ = 'A'; 871 #ifdef FSHLOCK /* currently gone */ 872 if (fp->f_flag & FSHLOCK) 873 *fbp++ = 'S'; 874 if (fp->f_flag & FEXLOCK) 875 *fbp++ = 'X'; 876 #endif 877 if (fp->f_flag & FASYNC) 878 *fbp++ = 'I'; 879 *fbp = '\0'; 880 (void)printf("%6s %3d", flagbuf, fp->f_count); 881 (void)printf(" %3d", fp->f_msgcount); 882 (void)printf(" %8.1x", fp->f_data); 883 if (fp->f_offset < 0) 884 (void)printf(" %qx\n", fp->f_offset); 885 else 886 (void)printf(" %qd\n", fp->f_offset); 887 } 888 free(buf); 889 } 890 891 int 892 getfiles(abuf, alen) 893 char **abuf; 894 int *alen; 895 { 896 size_t len; 897 int mib[2]; 898 char *buf; 899 900 /* 901 * XXX 902 * Add emulation of KINFO_FILE here. 903 */ 904 if (memf != NULL) 905 errx(1, "files on dead kernel, not implemented\n"); 906 907 mib[0] = CTL_KERN; 908 mib[1] = KERN_FILE; 909 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 910 warn("sysctl: KERN_FILE"); 911 return (-1); 912 } 913 if ((buf = malloc(len)) == NULL) 914 err(1, NULL); 915 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 916 warn("sysctl: KERN_FILE"); 917 return (-1); 918 } 919 *abuf = buf; 920 *alen = len; 921 return (0); 922 } 923 924 /* 925 * swapmode is based on a program called swapinfo written 926 * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 927 */ 928 void 929 swapmode() 930 { 931 char *header; 932 int hlen, nswap, nswdev, dmmax, nswapmap, niswap, niswdev; 933 int s, e, div, i, l, avail, nfree, npfree, used; 934 struct swdevt *sw; 935 long blocksize, *perdev; 936 struct map *swapmap, *kswapmap; 937 struct mapent *mp; 938 939 KGET(VM_NSWAP, nswap); 940 KGET(VM_NSWDEV, nswdev); 941 KGET(VM_DMMAX, dmmax); 942 KGET(VM_NSWAPMAP, nswapmap); 943 KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */ 944 if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || 945 (perdev = malloc(nswdev * sizeof(*perdev))) == NULL || 946 (mp = malloc(nswapmap * sizeof(*mp))) == NULL) 947 err(1, "malloc"); 948 KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt"); 949 KGET2((long)kswapmap, mp, nswapmap * sizeof(*mp), "swapmap"); 950 951 /* Supports sequential swap */ 952 if (nl[VM_NISWAP].n_value != 0) { 953 KGET(VM_NISWAP, niswap); 954 KGET(VM_NISWDEV, niswdev); 955 } else { 956 niswap = nswap; 957 niswdev = nswdev; 958 } 959 960 /* First entry in map is `struct map'; rest are mapent's. */ 961 swapmap = (struct map *)mp; 962 if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap) 963 errx(1, "panic: nswapmap goof"); 964 965 /* Count up swap space. */ 966 nfree = 0; 967 memset(perdev, 0, nswdev * sizeof(*perdev)); 968 for (mp++; mp->m_addr != 0; mp++) { 969 s = mp->m_addr; /* start of swap region */ 970 e = mp->m_addr + mp->m_size; /* end of region */ 971 nfree += mp->m_size; 972 973 /* 974 * Swap space is split up among the configured disks. 975 * 976 * For interleaved swap devices, the first dmmax blocks 977 * of swap space some from the first disk, the next dmmax 978 * blocks from the next, and so on up to niswap blocks. 979 * 980 * Sequential swap devices follow the interleaved devices 981 * (i.e. blocks starting at niswap) in the order in which 982 * they appear in the swdev table. The size of each device 983 * will be a multiple of dmmax. 984 * 985 * The list of free space joins adjacent free blocks, 986 * ignoring device boundries. If we want to keep track 987 * of this information per device, we'll just have to 988 * extract it ourselves. We know that dmmax-sized chunks 989 * cannot span device boundaries (interleaved or sequential) 990 * so we loop over such chunks assigning them to devices. 991 */ 992 i = -1; 993 while (s < e) { /* XXX this is inefficient */ 994 int bound = roundup(s+1, dmmax); 995 996 if (bound > e) 997 bound = e; 998 if (bound <= niswap) { 999 /* Interleaved swap chunk. */ 1000 if (i == -1) 1001 i = (s / dmmax) % niswdev; 1002 perdev[i] += bound - s; 1003 if (++i >= niswdev) 1004 i = 0; 1005 } else { 1006 /* Sequential swap chunk. */ 1007 if (i < niswdev) { 1008 i = niswdev; 1009 l = niswap + sw[i].sw_nblks; 1010 } 1011 while (s >= l) { 1012 /* XXX don't die on bogus blocks */ 1013 if (i == nswdev-1) 1014 break; 1015 l += sw[++i].sw_nblks; 1016 } 1017 perdev[i] += bound - s; 1018 } 1019 s = bound; 1020 } 1021 } 1022 1023 header = getbsize(&hlen, &blocksize); 1024 if (!totalflag) 1025 (void)printf("%-11s %*s %8s %8s %8s %s\n", 1026 "Device", hlen, header, 1027 "Used", "Avail", "Capacity", "Type"); 1028 div = blocksize / 512; 1029 avail = npfree = 0; 1030 for (i = 0; i < nswdev; i++) { 1031 int xsize, xfree; 1032 1033 if (!totalflag) 1034 (void)printf("/dev/%-6s %*d ", 1035 devname(sw[i].sw_dev, S_IFBLK), 1036 hlen, sw[i].sw_nblks / div); 1037 1038 /* 1039 * Don't report statistics for partitions which have not 1040 * yet been activated via swapon(8). 1041 */ 1042 if (!(sw[i].sw_flags & SW_FREED)) { 1043 if (totalflag) 1044 continue; 1045 (void)printf(" *** not available for swapping ***\n"); 1046 continue; 1047 } 1048 xsize = sw[i].sw_nblks; 1049 xfree = perdev[i]; 1050 used = xsize - xfree; 1051 npfree++; 1052 avail += xsize; 1053 if (totalflag) 1054 continue; 1055 (void)printf("%8d %8d %5.0f%% %s\n", 1056 used / div, xfree / div, 1057 (double)used / (double)xsize * 100.0, 1058 (sw[i].sw_flags & SW_SEQUENTIAL) ? 1059 "Sequential" : "Interleaved"); 1060 } 1061 1062 /* 1063 * If only one partition has been set up via swapon(8), we don't 1064 * need to bother with totals. 1065 */ 1066 used = avail - nfree; 1067 if (totalflag) { 1068 (void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048); 1069 return; 1070 } 1071 if (npfree > 1) { 1072 (void)printf("%-11s %*d %8d %8d %5.0f%%\n", 1073 "Total", hlen, avail / div, used / div, nfree / div, 1074 (double)used / (double)avail * 100.0); 1075 } 1076 } 1077 1078 void 1079 usage() 1080 { 1081 (void)fprintf(stderr, 1082 "usage: pstat -Tfnstv [system] [-M core] [-N system]\n"); 1083 exit(1); 1084 } 1085