1 /* $NetBSD: pstat.c,v 1.62 2001/10/26 05:56:11 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95"; 45 #else 46 __RCSID("$NetBSD: pstat.c,v 1.62 2001/10/26 05:56:11 lukem Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #include <sys/time.h> 52 #include <sys/vnode.h> 53 #include <sys/map.h> 54 #include <sys/ucred.h> 55 #define _KERNEL 56 #include <sys/file.h> 57 #include <ufs/ufs/inode.h> 58 #define NFS 59 #include <sys/mount.h> 60 #undef NFS 61 #include <sys/uio.h> 62 #include <sys/namei.h> 63 #include <miscfs/genfs/layer.h> 64 #include <miscfs/union/union.h> 65 #undef _KERNEL 66 #include <sys/stat.h> 67 #include <nfs/nfsproto.h> 68 #include <nfs/rpcv2.h> 69 #include <nfs/nfs.h> 70 #include <nfs/nfsnode.h> 71 #include <sys/ioctl.h> 72 #include <sys/tty.h> 73 #include <sys/conf.h> 74 #include <sys/device.h> 75 76 #include <sys/sysctl.h> 77 78 #include <err.h> 79 #include <kvm.h> 80 #include <limits.h> 81 #include <nlist.h> 82 #include <stdio.h> 83 #include <stdlib.h> 84 #include <string.h> 85 #include <unistd.h> 86 87 #include "swapctl.h" 88 89 struct nlist nl[] = { 90 #define V_MOUNTLIST 0 91 { "_mountlist" }, /* address of head of mount list. */ 92 #define V_NUMV 1 93 { "_numvnodes" }, 94 #define FNL_NFILE 2 95 { "_nfiles" }, 96 #define FNL_MAXFILE 3 97 { "_maxfiles" }, 98 #define TTY_NTTY 4 99 { "_tty_count" }, 100 #define TTY_TTYLIST 5 101 { "_ttylist" }, 102 #define NLMANDATORY TTY_TTYLIST /* names up to here are mandatory */ 103 { "" } 104 }; 105 106 int usenumflag; 107 int totalflag; 108 int kflag; 109 char *nlistf = NULL; 110 char *memf = NULL; 111 kvm_t *kd; 112 113 struct { 114 int m_flag; 115 const char *m_name; 116 } mnt_flags[] = { 117 { MNT_RDONLY, "rdonly" }, 118 { MNT_SYNCHRONOUS, "sync" }, 119 { MNT_NOEXEC, "noexec" }, 120 { MNT_NOSUID, "nosuid" }, 121 { MNT_NODEV, "nodev" }, 122 { MNT_UNION, "union" }, 123 { MNT_ASYNC, "async" }, 124 { MNT_NOCOREDUMP, "nocoredump" }, 125 { MNT_NOATIME, "noatime" }, 126 { MNT_SYMPERM, "symperm" }, 127 { MNT_NODEVMTIME, "nodevmtime" }, 128 { MNT_SOFTDEP, "softdep" }, 129 { MNT_EXRDONLY, "exrdonly" }, 130 { MNT_EXPORTED, "exported" }, 131 { MNT_DEFEXPORTED, "defexported" }, 132 { MNT_EXPORTANON, "exportanon" }, 133 { MNT_EXKERB, "exkerb" }, 134 { MNT_EXNORESPORT, "exnoresport" }, 135 { MNT_EXPUBLIC, "expublic" }, 136 { MNT_LOCAL, "local" }, 137 { MNT_QUOTA, "quota" }, 138 { MNT_ROOTFS, "rootfs" }, 139 { MNT_UPDATE, "update" }, 140 { MNT_DELEXPORT, "delexport" }, 141 { MNT_RELOAD, "reload" }, 142 { MNT_FORCE, "force" }, 143 { MNT_GONE, "gone" }, 144 { MNT_UNMOUNT, "unmount" }, 145 { MNT_WANTRDWR, "wantrdwr" }, 146 { 0 } 147 }; 148 149 #define SVAR(var) __STRING(var) /* to force expansion */ 150 #define KGET(idx, var) \ 151 KGET1(idx, &var, sizeof(var), SVAR(var)) 152 #define KGET1(idx, p, s, msg) \ 153 KGET2(nl[idx].n_value, p, s, msg) 154 #define KGET2(addr, p, s, msg) do { \ 155 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 156 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 157 } while (/* CONSTCOND */0) 158 #define KGETRET(addr, p, s, msg) do { \ 159 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 160 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 161 return (0); \ 162 } \ 163 } while (/* CONSTCOND */0) 164 165 void filemode __P((void)); 166 int getfiles __P((char **, int *)); 167 struct mount * 168 getmnt __P((struct mount *)); 169 char * kinfo_vnodes __P((int *)); 170 void layer_header __P((void)); 171 int layer_print __P((struct vnode *)); 172 char * loadvnodes __P((int *)); 173 int main __P((int, char **)); 174 void mount_print __P((struct mount *)); 175 void nfs_header __P((void)); 176 int nfs_print __P((struct vnode *)); 177 void ttymode __P((void)); 178 void ttyprt __P((struct tty *)); 179 void ufs_getflags __P((struct vnode *, struct inode *, char *)); 180 void ufs_header __P((void)); 181 int ufs_print __P((struct vnode *)); 182 int ext2fs_print __P((struct vnode *)); 183 void union_header __P((void)); 184 int union_print __P((struct vnode *)); 185 void usage __P((void)); 186 void vnode_header __P((void)); 187 void vnode_print __P((struct vnode *, struct vnode *)); 188 void vnodemode __P((void)); 189 190 int 191 main(argc, argv) 192 int argc; 193 char *argv[]; 194 { 195 int ch, i, quit, ret; 196 int fileflag, swapflag, ttyflag, vnodeflag; 197 gid_t egid = getegid(); 198 char buf[_POSIX2_LINE_MAX]; 199 200 setegid(getgid()); 201 fileflag = swapflag = ttyflag = vnodeflag = 0; 202 while ((ch = getopt(argc, argv, "TM:N:fiknstv")) != -1) 203 switch (ch) { 204 case 'f': 205 fileflag = 1; 206 break; 207 case 'M': 208 memf = optarg; 209 break; 210 case 'N': 211 nlistf = optarg; 212 break; 213 case 'n': 214 usenumflag = 1; 215 break; 216 case 's': 217 swapflag = 1; 218 break; 219 case 'T': 220 totalflag = 1; 221 break; 222 case 't': 223 ttyflag = 1; 224 break; 225 case 'k': 226 kflag = 1; 227 break; 228 case 'v': 229 case 'i': /* Backward compatibility. */ 230 vnodeflag = 1; 231 break; 232 default: 233 usage(); 234 } 235 argc -= optind; 236 argv += optind; 237 238 /* 239 * Discard setgid privileges. If not the running kernel, we toss 240 * them away totally so that bad guys can't print interesting stuff 241 * from kernel memory, otherwise switch back to kmem for the 242 * duration of the kvm_openfiles() call. 243 */ 244 if (nlistf != NULL || memf != NULL) 245 (void)setgid(getgid()); 246 else 247 (void)setegid(egid); 248 249 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 250 errx(1, "kvm_openfiles: %s", buf); 251 252 /* get rid of it now anyway */ 253 if (nlistf == NULL && memf == NULL) 254 (void)setgid(getgid()); 255 if ((ret = kvm_nlist(kd, nl)) != 0) { 256 if (ret == -1) 257 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 258 for (i = quit = 0; i <= NLMANDATORY; i++) 259 if (!nl[i].n_value) { 260 quit = 1; 261 warnx("undefined symbol: %s", nl[i].n_name); 262 } 263 if (quit) 264 exit(1); 265 } 266 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) 267 usage(); 268 if (fileflag || totalflag) 269 filemode(); 270 if (vnodeflag || totalflag) 271 vnodemode(); 272 if (ttyflag) 273 ttymode(); 274 if (swapflag || totalflag) 275 list_swap(0, kflag, 0, totalflag, 1); 276 exit (0); 277 } 278 279 #define VPTRSZ sizeof(struct vnode *) 280 #define VNODESZ sizeof(struct vnode) 281 282 void 283 vnodemode() 284 { 285 char *e_vnodebase, *endvnode, *evp; 286 struct vnode *vp; 287 struct mount *maddr, *mp; 288 int numvnodes; 289 int (*vnode_fsprint) __P((struct vnode *)); /* per-fs data printer */ 290 291 mp = NULL; 292 e_vnodebase = loadvnodes(&numvnodes); 293 if (totalflag) { 294 (void)printf("%7d vnodes\n", numvnodes); 295 return; 296 } 297 endvnode = e_vnodebase + numvnodes * (VPTRSZ + VNODESZ); 298 (void)printf("%d active vnodes\n", numvnodes); 299 300 #define ST mp->mnt_stat 301 #define FSTYPE_IS(mp, name) \ 302 (strncmp((mp)->mnt_stat.f_fstypename, (name), MFSNAMELEN) == 0) 303 maddr = NULL; 304 vnode_fsprint = NULL; 305 for (evp = e_vnodebase; evp < endvnode; evp += VPTRSZ + VNODESZ) { 306 vp = (struct vnode *)(evp + VPTRSZ); 307 if (vp->v_mount != maddr) { 308 /* 309 * New filesystem 310 */ 311 if ((mp = getmnt(vp->v_mount)) == NULL) 312 continue; 313 maddr = vp->v_mount; 314 mount_print(mp); 315 vnode_header(); 316 if (FSTYPE_IS(mp, MOUNT_FFS) || 317 FSTYPE_IS(mp, MOUNT_MFS)) { 318 ufs_header(); 319 vnode_fsprint = ufs_print; 320 } else if (FSTYPE_IS(mp, MOUNT_NFS)) { 321 nfs_header(); 322 vnode_fsprint = nfs_print; 323 } else if (FSTYPE_IS(mp, MOUNT_EXT2FS)) { 324 ufs_header(); 325 vnode_fsprint = ext2fs_print; 326 } else if (FSTYPE_IS(mp, MOUNT_NULL) || 327 FSTYPE_IS(mp, MOUNT_OVERLAY) || 328 FSTYPE_IS(mp, MOUNT_UMAP)) { 329 layer_header(); 330 vnode_fsprint = layer_print; 331 } else if (FSTYPE_IS(mp, MOUNT_UNION)) { 332 union_header(); 333 vnode_fsprint = union_print; 334 } else 335 vnode_fsprint = NULL; 336 (void)printf("\n"); 337 } 338 vnode_print(*(struct vnode **)evp, vp); 339 if (VTOI(vp) != NULL && vnode_fsprint != NULL) 340 (*vnode_fsprint)(vp); 341 (void)printf("\n"); 342 } 343 free(e_vnodebase); 344 } 345 346 void 347 vnode_header() 348 { 349 350 (void)printf("ADDR TYP VFLAG USE HOLD TAG"); 351 } 352 353 void 354 vnode_print(avnode, vp) 355 struct vnode *avnode; 356 struct vnode *vp; 357 { 358 char *type, flags[16]; 359 char *fp = flags; 360 int flag; 361 362 /* 363 * set type 364 */ 365 switch (vp->v_type) { 366 case VNON: 367 type = "non"; break; 368 case VREG: 369 type = "reg"; break; 370 case VDIR: 371 type = "dir"; break; 372 case VBLK: 373 type = "blk"; break; 374 case VCHR: 375 type = "chr"; break; 376 case VLNK: 377 type = "lnk"; break; 378 case VSOCK: 379 type = "soc"; break; 380 case VFIFO: 381 type = "fif"; break; 382 case VBAD: 383 type = "bad"; break; 384 default: 385 type = "unk"; break; 386 } 387 /* 388 * gather flags 389 */ 390 flag = vp->v_flag; 391 if (flag & VROOT) 392 *fp++ = 'R'; 393 if (flag & VTEXT) 394 *fp++ = 'T'; 395 if (flag & VSYSTEM) 396 *fp++ = 'S'; 397 if (flag & VISTTY) 398 *fp++ = 'I'; 399 if (flag & VXLOCK) 400 *fp++ = 'L'; 401 if (flag & VXWANT) 402 *fp++ = 'W'; 403 if (flag & VBWAIT) 404 *fp++ = 'B'; 405 if (flag & VALIASED) 406 *fp++ = 'A'; 407 if (flag & VDIROP) 408 *fp++ = 'D'; 409 if (flag & VLAYER) 410 *fp++ = 'Y'; 411 if (flag & VONWORKLST) 412 *fp++ = 'O'; 413 if (flag == 0) 414 *fp++ = '-'; 415 *fp = '\0'; 416 (void)printf("%8lx %s %5s %4ld %4ld %3d", 417 (long)avnode, type, flags, (long)vp->v_usecount, 418 (long)vp->v_holdcnt, vp->v_tag); 419 } 420 421 void 422 ufs_getflags(vp, ip, flags) 423 struct vnode *vp; 424 struct inode *ip; 425 char *flags; 426 { 427 int flag; 428 429 /* 430 * XXX need to to locking state. 431 */ 432 433 flag = ip->i_flag; 434 if (flag & IN_ACCESS) 435 *flags++ = 'A'; 436 if (flag & IN_CHANGE) 437 *flags++ = 'C'; 438 if (flag & IN_UPDATE) 439 *flags++ = 'U'; 440 if (flag & IN_MODIFIED) 441 *flags++ = 'M'; 442 if (flag & IN_ACCESSED) 443 *flags++ = 'a'; 444 if (flag & IN_RENAME) 445 *flags++ = 'R'; 446 if (flag & IN_SHLOCK) 447 *flags++ = 'S'; 448 if (flag & IN_EXLOCK) 449 *flags++ = 'E'; 450 if (flag & IN_CLEANING) 451 *flags++ = 'c'; 452 if (flag & IN_ADIROP) 453 *flags++ = 'a'; 454 if (flag == 0) 455 *flags++ = '-'; 456 *flags = '\0'; 457 458 } 459 460 void 461 ufs_header() 462 { 463 464 (void)printf(" FILEID IFLAG RDEV|SZ"); 465 } 466 467 int 468 ufs_print(vp) 469 struct vnode *vp; 470 { 471 struct inode inode, *ip = &inode; 472 char flagbuf[16]; 473 char *name; 474 mode_t type; 475 476 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 477 ufs_getflags(vp, ip, flagbuf); 478 (void)printf(" %6d %5s", ip->i_number, flagbuf); 479 type = ip->i_ffs_mode & S_IFMT; 480 if (S_ISCHR(ip->i_ffs_mode) || S_ISBLK(ip->i_ffs_mode)) 481 if (usenumflag || 482 ((name = devname(ip->i_ffs_rdev, type)) == NULL)) 483 (void)printf(" %2d,%-2d", 484 major(ip->i_ffs_rdev), minor(ip->i_ffs_rdev)); 485 else 486 (void)printf(" %7s", name); 487 else 488 (void)printf(" %7lld", (long long)ip->i_ffs_size); 489 return (0); 490 } 491 492 int 493 ext2fs_print(vp) 494 struct vnode *vp; 495 { 496 struct inode inode, *ip = &inode; 497 char flagbuf[16]; 498 char *name; 499 mode_t type; 500 501 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 502 ufs_getflags(vp, ip, flagbuf); 503 (void)printf(" %6d %5s", ip->i_number, flagbuf); 504 type = ip->i_e2fs_mode & S_IFMT; 505 if (S_ISCHR(ip->i_e2fs_mode) || S_ISBLK(ip->i_e2fs_mode)) 506 if (usenumflag || 507 ((name = devname(ip->i_e2fs_rdev, type)) == NULL)) 508 (void)printf(" %2d,%-2d", 509 major(ip->i_e2fs_rdev), minor(ip->i_e2fs_rdev)); 510 else 511 (void)printf(" %7s", name); 512 else 513 (void)printf(" %7u", (u_int)ip->i_e2fs_size); 514 return (0); 515 } 516 517 void 518 nfs_header() 519 { 520 521 (void)printf(" FILEID NFLAG RDEV|SZ"); 522 } 523 524 int 525 nfs_print(vp) 526 struct vnode *vp; 527 { 528 struct nfsnode nfsnode, *np = &nfsnode; 529 char flagbuf[16], *flags = flagbuf; 530 int flag; 531 struct vattr va; 532 char *name; 533 mode_t type; 534 535 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); 536 flag = np->n_flag; 537 if (flag & NFLUSHWANT) 538 *flags++ = 'W'; 539 if (flag & NFLUSHINPROG) 540 *flags++ = 'P'; 541 if (flag & NMODIFIED) 542 *flags++ = 'M'; 543 if (flag & NWRITEERR) 544 *flags++ = 'E'; 545 if (flag & NQNFSNONCACHE) 546 *flags++ = 'X'; 547 if (flag & NQNFSWRITE) 548 *flags++ = 'O'; 549 if (flag & NQNFSEVICTED) 550 *flags++ = 'G'; 551 if (flag & NACC) 552 *flags++ = 'A'; 553 if (flag & NUPD) 554 *flags++ = 'U'; 555 if (flag & NCHG) 556 *flags++ = 'C'; 557 if (flag == 0) 558 *flags++ = '-'; 559 *flags = '\0'; 560 561 KGETRET(np->n_vattr, &va, sizeof(va), "vnode attr"); 562 (void)printf(" %6ld %5s", (long)va.va_fileid, flagbuf); 563 switch (va.va_type) { 564 case VCHR: 565 type = S_IFCHR; 566 goto device; 567 568 case VBLK: 569 type = S_IFBLK; 570 device: 571 if (usenumflag || ((name = devname(va.va_rdev, type)) == NULL)) 572 (void)printf(" %2d,%-2d", 573 major(va.va_rdev), minor(va.va_rdev)); 574 else 575 (void)printf(" %7s", name); 576 break; 577 default: 578 (void)printf(" %7lld", (long long)np->n_size); 579 break; 580 } 581 return (0); 582 } 583 584 void 585 layer_header() 586 { 587 588 (void)printf(" LOWER"); 589 } 590 591 int 592 layer_print(vp) 593 struct vnode *vp; 594 { 595 struct layer_node lnode, *lp = &lnode; 596 597 KGETRET(VTOLAYER(vp), &lnode, sizeof(lnode), "layer vnode"); 598 599 (void)printf(" %8lx", (long)lp->layer_lowervp); 600 return (0); 601 } 602 603 void 604 union_header() 605 { 606 607 (void)printf(" UPPER LOWER"); 608 } 609 610 int 611 union_print(vp) 612 struct vnode *vp; 613 { 614 struct union_node unode, *up = &unode; 615 616 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode"); 617 618 (void)printf(" %8lx %8lx", (long)up->un_uppervp, (long)up->un_lowervp); 619 return (0); 620 } 621 622 /* 623 * Given a pointer to a mount structure in kernel space, 624 * read it in and return a usable pointer to it. 625 */ 626 struct mount * 627 getmnt(maddr) 628 struct mount *maddr; 629 { 630 static struct mtab { 631 struct mtab *next; 632 struct mount *maddr; 633 struct mount mount; 634 } *mhead = NULL; 635 struct mtab *mt; 636 637 for (mt = mhead; mt != NULL; mt = mt->next) 638 if (maddr == mt->maddr) 639 return (&mt->mount); 640 if ((mt = malloc(sizeof(struct mtab))) == NULL) 641 err(1, "malloc"); 642 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); 643 mt->maddr = maddr; 644 mt->next = mhead; 645 mhead = mt; 646 return (&mt->mount); 647 } 648 649 void 650 mount_print(mp) 651 struct mount *mp; 652 { 653 int flags; 654 655 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename, 656 ST.f_mntfromname, ST.f_mntonname); 657 if ((flags = mp->mnt_flag) != 0) { 658 int i; 659 const char *sep = " ("; 660 661 for (i = 0; mnt_flags[i].m_flag; i++) { 662 if (flags & mnt_flags[i].m_flag) { 663 (void)printf("%s%s", sep, mnt_flags[i].m_name); 664 flags &= ~mnt_flags[i].m_flag; 665 sep = ","; 666 } 667 } 668 if (flags) 669 (void)printf("%sunknown_flags:%x", sep, flags); 670 (void)printf(")"); 671 } 672 (void)printf("\n"); 673 } 674 675 char * 676 loadvnodes(avnodes) 677 int *avnodes; 678 { 679 int mib[2]; 680 size_t copysize; 681 char *vnodebase; 682 683 if (memf != NULL) { 684 /* 685 * do it by hand 686 */ 687 return (kinfo_vnodes(avnodes)); 688 } 689 mib[0] = CTL_KERN; 690 mib[1] = KERN_VNODE; 691 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) 692 err(1, "sysctl: KERN_VNODE"); 693 if ((vnodebase = malloc(copysize)) == NULL) 694 err(1, "malloc"); 695 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) 696 err(1, "sysctl: KERN_VNODE"); 697 if (copysize % (VPTRSZ + VNODESZ)) 698 errx(1, "vnode size mismatch"); 699 *avnodes = copysize / (VPTRSZ + VNODESZ); 700 701 return (vnodebase); 702 } 703 704 /* 705 * simulate what a running kernel does in in kinfo_vnode 706 */ 707 char * 708 kinfo_vnodes(avnodes) 709 int *avnodes; 710 { 711 struct mntlist mountlist; 712 struct mount *mp, mount; 713 struct vnode *vp, vnode; 714 char *beg, *bp, *ep; 715 int numvnodes; 716 717 KGET(V_NUMV, numvnodes); 718 if ((bp = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL) 719 err(1, "malloc"); 720 beg = bp; 721 ep = bp + (numvnodes + 20) * (VPTRSZ + VNODESZ); 722 KGET(V_MOUNTLIST, mountlist); 723 for (mp = mountlist.cqh_first;; 724 mp = mount.mnt_list.cqe_next) { 725 KGET2(mp, &mount, sizeof(mount), "mount entry"); 726 for (vp = mount.mnt_vnodelist.lh_first; 727 vp != NULL; vp = vnode.v_mntvnodes.le_next) { 728 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 729 if (bp + VPTRSZ + VNODESZ > ep) 730 /* XXX - should realloc */ 731 errx(1, "no more room for vnodes"); 732 memmove(bp, &vp, VPTRSZ); 733 bp += VPTRSZ; 734 memmove(bp, &vnode, VNODESZ); 735 bp += VNODESZ; 736 } 737 if (mp == mountlist.cqh_last) 738 break; 739 } 740 *avnodes = (bp - beg) / (VPTRSZ + VNODESZ); 741 return (beg); 742 } 743 744 const char hdr[]=" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n"; 745 int ttyspace = 128; 746 747 void 748 ttymode() 749 { 750 int ntty; 751 struct ttylist_head tty_head; 752 struct tty *tp, tty; 753 754 KGET(TTY_NTTY, ntty); 755 (void)printf("%d terminal device%s\n", ntty, ntty == 1 ? "" : "s"); 756 KGET(TTY_TTYLIST, tty_head); 757 (void)printf(hdr); 758 for (tp = tty_head.tqh_first; tp; tp = tty.tty_link.tqe_next) { 759 KGET2(tp, &tty, sizeof tty, "tty struct"); 760 ttyprt(&tty); 761 } 762 } 763 764 struct { 765 int flag; 766 char val; 767 } ttystates[] = { 768 { TS_ISOPEN, 'O'}, 769 { TS_DIALOUT, '>'}, 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) 789 struct tty *tp; 790 { 791 int i, j; 792 pid_t pgid; 793 char *name, state[20], buffer; 794 struct linesw t_linesw; 795 796 if (usenumflag || (name = devname(tp->t_dev, S_IFCHR)) == NULL) 797 (void)printf("0x%3x:%1x ", major(tp->t_dev), minor(tp->t_dev)); 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 %7d ", 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 (tp->t_wopen) 807 state[j++] = 'W'; 808 if (j == 0) 809 state[j++] = '-'; 810 state[j] = '\0'; 811 (void)printf("%-6s %8lX", state, (u_long)tp->t_session); 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 KGET2(tp->t_linesw, &t_linesw, sizeof(t_linesw), 817 "line discipline switch table"); 818 name = t_linesw.l_name; 819 for (;;) { 820 KGET2(name, &buffer, sizeof(buffer), "line discipline name"); 821 if (buffer == '\0') 822 break; 823 (void)putchar(buffer); 824 name++; 825 } 826 (void)putchar('\n'); 827 } 828 829 void 830 filemode() 831 { 832 struct file *fp; 833 struct file *addr; 834 char *buf, flagbuf[16], *fbp; 835 int len, maxfile, nfile; 836 static char *dtypes[] = { "???", "inode", "socket" }; 837 838 KGET(FNL_MAXFILE, maxfile); 839 if (totalflag) { 840 KGET(FNL_NFILE, nfile); 841 (void)printf("%3d/%3d files\n", nfile, maxfile); 842 return; 843 } 844 if (getfiles(&buf, &len) == -1) 845 return; 846 /* 847 * Getfiles returns in malloc'd memory a pointer to the first file 848 * structure, and then an array of file structs (whose addresses are 849 * derivable from the previous entry). 850 */ 851 addr = ((struct filelist *)buf)->lh_first; 852 fp = (struct file *)(buf + sizeof(struct filelist)); 853 nfile = (len - sizeof(struct filelist)) / sizeof(struct file); 854 855 (void)printf("%d/%d open files\n", nfile, maxfile); 856 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 857 for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) { 858 if ((unsigned)fp->f_type > DTYPE_SOCKET) 859 continue; 860 (void)printf("%lx ", (long)addr); 861 (void)printf("%-8.8s", dtypes[fp->f_type]); 862 fbp = flagbuf; 863 if (fp->f_flag & FREAD) 864 *fbp++ = 'R'; 865 if (fp->f_flag & FWRITE) 866 *fbp++ = 'W'; 867 if (fp->f_flag & FAPPEND) 868 *fbp++ = 'A'; 869 #ifdef FSHLOCK /* currently gone */ 870 if (fp->f_flag & FSHLOCK) 871 *fbp++ = 'S'; 872 if (fp->f_flag & FEXLOCK) 873 *fbp++ = 'X'; 874 #endif 875 if (fp->f_flag & FASYNC) 876 *fbp++ = 'I'; 877 *fbp = '\0'; 878 (void)printf("%6s %3d", flagbuf, fp->f_count); 879 (void)printf(" %3d", fp->f_msgcount); 880 (void)printf(" %8.1lx", (long)fp->f_data); 881 if (fp->f_offset < 0) 882 (void)printf(" %llx\n", (long long)fp->f_offset); 883 else 884 (void)printf(" %lld\n", (long long)fp->f_offset); 885 } 886 free(buf); 887 } 888 889 int 890 getfiles(abuf, alen) 891 char **abuf; 892 int *alen; 893 { 894 size_t len; 895 int mib[2]; 896 char *buf; 897 898 /* 899 * XXX 900 * Add emulation of KINFO_FILE here. 901 */ 902 if (memf != NULL) 903 errx(1, "files on dead kernel, not implemented"); 904 905 mib[0] = CTL_KERN; 906 mib[1] = KERN_FILE; 907 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 908 warn("sysctl: KERN_FILE"); 909 return (-1); 910 } 911 if ((buf = malloc(len)) == NULL) 912 err(1, "malloc"); 913 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 914 warn("sysctl: KERN_FILE"); 915 return (-1); 916 } 917 *abuf = buf; 918 *alen = len; 919 return (0); 920 } 921 922 void 923 usage() 924 { 925 926 (void)fprintf(stderr, 927 "usage: pstat [-T|-f|-s|-t|-v] [-kn] [-M core] [-N system]\n"); 928 exit(1); 929 } 930