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