1 /* $NetBSD: pstat.c,v 1.72 2002/02/24 02:02:59 enami 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.72 2002/02/24 02:02:59 enami 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 u_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 struct flagbit_desc { 150 u_int fd_flags; 151 char fd_mark; 152 }; 153 154 #define SVAR(var) __STRING(var) /* to force expansion */ 155 #define KGET(idx, var) \ 156 KGET1(idx, &var, sizeof(var), SVAR(var)) 157 #define KGET1(idx, p, s, msg) \ 158 KGET2(nl[idx].n_value, p, s, msg) 159 #define KGET2(addr, p, s, msg) do { \ 160 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 161 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 162 } while (/* CONSTCOND */0) 163 #define KGETRET(addr, p, s, msg) do { \ 164 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 165 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 166 return (0); \ 167 } \ 168 } while (/* CONSTCOND */0) 169 170 #if 1 /* This is copied from vmstat/vmstat.c */ 171 /* 172 * Print single word. `ovflow' is number of characters didn't fit 173 * on the last word. `fmt' is a format string to print this word. 174 * It must contain asterisk for field width. `width' is a width 175 * occupied by this word. `fixed' is a number of constant chars in 176 * `fmt'. `val' is a value to be printed using format string `fmt'. 177 */ 178 #define PRWORD(ovflw, fmt, width, fixed, val) do { \ 179 (ovflw) += printf((fmt), \ 180 (width) - (fixed) - (ovflw) > 0 ? \ 181 (width) - (fixed) - (ovflw) : 0, \ 182 (val)) - (width); \ 183 if ((ovflw) < 0) \ 184 (ovflw) = 0; \ 185 } while (/* CONSTCOND */0) 186 #endif 187 188 void filemode __P((void)); 189 int getfiles __P((char **, int *)); 190 int getflags __P((const struct flagbit_desc *, char *, u_int)); 191 struct mount * 192 getmnt __P((struct mount *)); 193 char * kinfo_vnodes __P((int *)); 194 void layer_header __P((void)); 195 int layer_print __P((struct vnode *, int)); 196 char * loadvnodes __P((int *)); 197 int main __P((int, char **)); 198 void mount_print __P((struct mount *)); 199 void nfs_header __P((void)); 200 int nfs_print __P((struct vnode *, int)); 201 void ttymode __P((void)); 202 void ttyprt __P((struct tty *)); 203 void ufs_header __P((void)); 204 int ufs_print __P((struct vnode *, int)); 205 int ext2fs_print __P((struct vnode *, int)); 206 void union_header __P((void)); 207 int union_print __P((struct vnode *, int)); 208 void usage __P((void)); 209 void vnode_header __P((void)); 210 int vnode_print __P((struct vnode *, struct vnode *)); 211 void vnodemode __P((void)); 212 213 int 214 main(argc, argv) 215 int argc; 216 char *argv[]; 217 { 218 int ch, i, quit, ret; 219 int fileflag, swapflag, ttyflag, vnodeflag; 220 gid_t egid = getegid(); 221 char buf[_POSIX2_LINE_MAX]; 222 223 setegid(getgid()); 224 fileflag = swapflag = ttyflag = vnodeflag = 0; 225 while ((ch = getopt(argc, argv, "TM:N:fiknstv")) != -1) 226 switch (ch) { 227 case 'f': 228 fileflag = 1; 229 break; 230 case 'M': 231 memf = optarg; 232 break; 233 case 'N': 234 nlistf = optarg; 235 break; 236 case 'n': 237 usenumflag = 1; 238 break; 239 case 's': 240 swapflag = 1; 241 break; 242 case 'T': 243 totalflag = 1; 244 break; 245 case 't': 246 ttyflag = 1; 247 break; 248 case 'k': 249 kflag = 1; 250 break; 251 case 'v': 252 case 'i': /* Backward compatibility. */ 253 vnodeflag = 1; 254 break; 255 default: 256 usage(); 257 } 258 argc -= optind; 259 argv += optind; 260 261 /* 262 * Discard setgid privileges. If not the running kernel, we toss 263 * them away totally so that bad guys can't print interesting stuff 264 * from kernel memory, otherwise switch back to kmem for the 265 * duration of the kvm_openfiles() call. 266 */ 267 if (nlistf != NULL || memf != NULL) 268 (void)setgid(getgid()); 269 else 270 (void)setegid(egid); 271 272 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 273 errx(1, "kvm_openfiles: %s", buf); 274 275 /* get rid of it now anyway */ 276 if (nlistf == NULL && memf == NULL) 277 (void)setgid(getgid()); 278 if ((ret = kvm_nlist(kd, nl)) != 0) { 279 if (ret == -1) 280 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 281 for (i = quit = 0; i <= NLMANDATORY; i++) 282 if (!nl[i].n_value) { 283 quit = 1; 284 warnx("undefined symbol: %s", nl[i].n_name); 285 } 286 if (quit) 287 exit(1); 288 } 289 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) 290 usage(); 291 if (fileflag || totalflag) 292 filemode(); 293 if (vnodeflag || totalflag) 294 vnodemode(); 295 if (ttyflag) 296 ttymode(); 297 if (swapflag || totalflag) 298 list_swap(0, kflag, 0, totalflag, 1); 299 exit(0); 300 } 301 302 #define VPTRSZ sizeof(struct vnode *) 303 #define VNODESZ sizeof(struct vnode) 304 #define PTRSTRWIDTH ((int)sizeof(void *) * 2) /* Width of resulting string 305 when pointer is printed 306 in hexadecimal. */ 307 308 void 309 vnodemode() 310 { 311 char *e_vnodebase, *endvnode, *evp; 312 struct vnode *vp; 313 struct mount *maddr, *mp; 314 int numvnodes, ovflw; 315 int (*vnode_fsprint) 316 __P((struct vnode *, int)); /* per-fs data printer */ 317 318 mp = NULL; 319 e_vnodebase = loadvnodes(&numvnodes); 320 if (totalflag) { 321 (void)printf("%7d vnodes\n", numvnodes); 322 goto out; 323 } 324 endvnode = e_vnodebase + numvnodes * (VPTRSZ + VNODESZ); 325 (void)printf("%d active vnodes\n", numvnodes); 326 327 #define ST mp->mnt_stat 328 #define FSTYPE_IS(mp, name) \ 329 (strncmp((mp)->mnt_stat.f_fstypename, (name), MFSNAMELEN) == 0) 330 maddr = NULL; 331 vnode_fsprint = NULL; 332 for (evp = e_vnodebase; evp < endvnode; evp += VPTRSZ + VNODESZ) { 333 vp = (struct vnode *)(evp + VPTRSZ); 334 if (vp->v_mount != maddr) { 335 /* 336 * New filesystem 337 */ 338 if ((mp = getmnt(vp->v_mount)) == NULL) 339 continue; 340 maddr = vp->v_mount; 341 mount_print(mp); 342 vnode_header(); 343 if (FSTYPE_IS(mp, MOUNT_FFS) || 344 FSTYPE_IS(mp, MOUNT_MFS)) { 345 ufs_header(); 346 vnode_fsprint = ufs_print; 347 } else if (FSTYPE_IS(mp, MOUNT_NFS)) { 348 nfs_header(); 349 vnode_fsprint = nfs_print; 350 } else if (FSTYPE_IS(mp, MOUNT_EXT2FS)) { 351 ufs_header(); 352 vnode_fsprint = ext2fs_print; 353 } else if (FSTYPE_IS(mp, MOUNT_NULL) || 354 FSTYPE_IS(mp, MOUNT_OVERLAY) || 355 FSTYPE_IS(mp, MOUNT_UMAP)) { 356 layer_header(); 357 vnode_fsprint = layer_print; 358 } else if (FSTYPE_IS(mp, MOUNT_UNION)) { 359 union_header(); 360 vnode_fsprint = union_print; 361 } else 362 vnode_fsprint = NULL; 363 (void)printf("\n"); 364 } 365 ovflw = vnode_print(*(struct vnode **)evp, vp); 366 if (VTOI(vp) != NULL && vnode_fsprint != NULL) 367 (*vnode_fsprint)(vp, ovflw); 368 (void)printf("\n"); 369 } 370 371 out: 372 free(e_vnodebase); 373 } 374 375 int 376 getflags(fd, p, flags) 377 const struct flagbit_desc *fd; 378 char *p; 379 u_int flags; 380 { 381 char *q = p; 382 383 if (flags == 0) { 384 *p++ = '-'; 385 *p = '\0'; 386 return (0); 387 } 388 389 for (; fd->fd_flags != 0; fd++) 390 if ((flags & fd->fd_flags) != 0) 391 *p++ = fd->fd_mark; 392 *p = '\0'; 393 return (p - q); 394 } 395 396 const struct flagbit_desc vnode_flags[] = { 397 { VROOT, 'R' }, 398 { VTEXT, 'T' }, 399 { VSYSTEM, 'S' }, 400 { VISTTY, 'I' }, 401 { VEXECMAP, 'E' }, 402 { VXLOCK, 'L' }, 403 { VXWANT, 'W' }, 404 { VBWAIT, 'B' }, 405 { VALIASED, 'A' }, 406 { VDIROP, 'D' }, 407 { VLAYER, 'Y' }, 408 { VONWORKLST, 'O' }, 409 { 0, '\0' }, 410 }; 411 412 void 413 vnode_header() 414 { 415 416 (void)printf("%-*s TYP VFLAG USE HOLD TAG NPAGE", 417 PTRSTRWIDTH, "ADDR"); 418 } 419 420 int 421 vnode_print(avnode, vp) 422 struct vnode *avnode; 423 struct vnode *vp; 424 { 425 char *type, flags[sizeof(vnode_flags) / sizeof(vnode_flags[0])]; 426 int ovflw; 427 428 /* 429 * set type 430 */ 431 switch (vp->v_type) { 432 case VNON: 433 type = "non"; break; 434 case VREG: 435 type = "reg"; break; 436 case VDIR: 437 type = "dir"; break; 438 case VBLK: 439 type = "blk"; break; 440 case VCHR: 441 type = "chr"; break; 442 case VLNK: 443 type = "lnk"; break; 444 case VSOCK: 445 type = "soc"; break; 446 case VFIFO: 447 type = "fif"; break; 448 case VBAD: 449 type = "bad"; break; 450 default: 451 type = "unk"; break; 452 } 453 /* 454 * gather flags 455 */ 456 (void)getflags(vnode_flags, flags, vp->v_flag); 457 458 ovflw = 0; 459 PRWORD(ovflw, "%*lx", PTRSTRWIDTH, 0, (long)avnode); 460 PRWORD(ovflw, " %*s", 4, 1, type); 461 PRWORD(ovflw, " %*s", 6, 1, flags); 462 PRWORD(ovflw, " %*ld", 5, 1, (long)vp->v_usecount); 463 PRWORD(ovflw, " %*ld", 5, 1, (long)vp->v_holdcnt); 464 PRWORD(ovflw, " %*d", 4, 1, vp->v_tag); 465 PRWORD(ovflw, " %*d", 6, 1, vp->v_uobj.uo_npages); 466 return (ovflw); 467 } 468 469 const struct flagbit_desc ufs_flags[] = { 470 { IN_ACCESS, 'A' }, 471 { IN_CHANGE, 'C' }, 472 { IN_UPDATE, 'U' }, 473 { IN_MODIFIED, 'M' }, 474 { IN_ACCESSED, 'a' }, 475 { IN_RENAME, 'R' }, 476 { IN_SHLOCK, 'S' }, 477 { IN_EXLOCK, 'E' }, 478 { IN_CLEANING, 'c' }, 479 { IN_ADIROP, 'D' }, 480 { IN_SPACECOUNTED, 's' }, 481 { 0, '\0' }, 482 }; 483 484 void 485 ufs_header() 486 { 487 488 (void)printf(" FILEID IFLAG RDEV|SZ"); 489 } 490 491 int 492 ufs_print(vp, ovflw) 493 struct vnode *vp; 494 int ovflw; 495 { 496 struct inode inode, *ip = &inode; 497 char flags[sizeof(ufs_flags) / sizeof(ufs_flags[0])]; 498 char dev[4 + 1 + 7 + 1]; /* 12bit marjor + 20bit minor */ 499 char *name; 500 mode_t type; 501 502 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 503 504 /* 505 * XXX need to to locking state. 506 */ 507 508 (void)getflags(ufs_flags, flags, ip->i_flag); 509 PRWORD(ovflw, " %*d", 7, 1, ip->i_number); 510 PRWORD(ovflw, " %*s", 6, 1, flags); 511 type = ip->i_ffs_mode & S_IFMT; 512 if (S_ISCHR(ip->i_ffs_mode) || S_ISBLK(ip->i_ffs_mode)) { 513 if (usenumflag || 514 (name = devname(ip->i_ffs_rdev, type)) == NULL) { 515 snprintf(dev, sizeof(dev), "%d,%d", 516 major(ip->i_ffs_rdev), minor(ip->i_ffs_rdev)); 517 name = dev; 518 } 519 PRWORD(ovflw, " %*s", 8, 1, name); 520 } else 521 PRWORD(ovflw, " %*lld", 8, 1, (long long)ip->i_ffs_size); 522 return (0); 523 } 524 525 int 526 ext2fs_print(vp, ovflw) 527 struct vnode *vp; 528 int ovflw; 529 { 530 struct inode inode, *ip = &inode; 531 char flags[sizeof(ufs_flags) / sizeof(ufs_flags[0])]; 532 char dev[4 + 1 + 7 + 1]; /* 12bit marjor + 20bit minor */ 533 char *name; 534 mode_t type; 535 536 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 537 538 /* 539 * XXX need to to locking state. 540 */ 541 542 (void)getflags(ufs_flags, flags, ip->i_flag); 543 PRWORD(ovflw, " %*d", 7, 1, ip->i_number); 544 PRWORD(ovflw, " %*s", 6, 1, flags); 545 type = ip->i_e2fs_mode & S_IFMT; 546 if (S_ISCHR(ip->i_e2fs_mode) || S_ISBLK(ip->i_e2fs_mode)) { 547 if (usenumflag || 548 (name = devname(ip->i_e2fs_rdev, type)) == NULL) { 549 snprintf(dev, sizeof(dev), "%d,%d", 550 major(ip->i_e2fs_rdev), minor(ip->i_e2fs_rdev)); 551 name = dev; 552 } 553 PRWORD(ovflw, " %*s", 8, 1, name); 554 } else 555 PRWORD(ovflw, " %*u", 8, 1, (u_int)ip->i_e2fs_size); 556 return (0); 557 } 558 559 const struct flagbit_desc nfs_flags[] = { 560 { NFLUSHWANT, 'W' }, 561 { NFLUSHINPROG, 'P' }, 562 { NMODIFIED, 'M' }, 563 { NWRITEERR, 'E' }, 564 { NQNFSNONCACHE, 'X' }, 565 { NQNFSWRITE, 'O' }, 566 { NQNFSEVICTED, 'G' }, 567 { NACC, 'A' }, 568 { NUPD, 'U' }, 569 { NCHG, 'C' }, 570 { 0, '\0' }, 571 }; 572 573 void 574 nfs_header() 575 { 576 577 (void)printf(" FILEID NFLAG RDEV|SZ"); 578 } 579 580 int 581 nfs_print(vp, ovflw) 582 struct vnode *vp; 583 int ovflw; 584 { 585 struct nfsnode nfsnode, *np = &nfsnode; 586 char flags[sizeof(nfs_flags) / sizeof(nfs_flags[0])]; 587 char dev[4 + 1 + 7 + 1]; /* 12bit marjor + 20bit minor */ 588 struct vattr va; 589 char *name; 590 mode_t type; 591 592 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); 593 (void)getflags(nfs_flags, flags, np->n_flag); 594 595 KGETRET(np->n_vattr, &va, sizeof(va), "vnode attr"); 596 PRWORD(ovflw, " %*ld", 7, 1, (long)va.va_fileid); 597 PRWORD(ovflw, " %*s", 6, 1, flags); 598 switch (va.va_type) { 599 case VCHR: 600 type = S_IFCHR; 601 goto device; 602 603 case VBLK: 604 type = S_IFBLK; 605 device: 606 if (usenumflag || (name = devname(va.va_rdev, type)) == NULL) { 607 (void)snprintf(dev, sizeof(dev), "%d,%d", 608 major(va.va_rdev), minor(va.va_rdev)); 609 name = dev; 610 } 611 PRWORD(ovflw, " %*s", 8, 1, name); 612 break; 613 default: 614 PRWORD(ovflw, " %*lld", 8, 1, (long long)np->n_size); 615 break; 616 } 617 return (0); 618 } 619 620 void 621 layer_header() 622 { 623 624 (void)printf(" %*s", PTRSTRWIDTH, "LOWER"); 625 } 626 627 int 628 layer_print(vp, ovflw) 629 struct vnode *vp; 630 int ovflw; 631 { 632 struct layer_node lnode, *lp = &lnode; 633 634 KGETRET(VTOLAYER(vp), &lnode, sizeof(lnode), "layer vnode"); 635 636 PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 1, (long)lp->layer_lowervp); 637 return (0); 638 } 639 640 void 641 union_header() 642 { 643 644 (void)printf(" %*s %*s", PTRSTRWIDTH, "UPPER", PTRSTRWIDTH, "LOWER"); 645 } 646 647 int 648 union_print(vp, ovflw) 649 struct vnode *vp; 650 int ovflw; 651 { 652 struct union_node unode, *up = &unode; 653 654 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode"); 655 656 PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 1, (long)up->un_uppervp); 657 PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 1, (long)up->un_lowervp); 658 return (0); 659 } 660 661 /* 662 * Given a pointer to a mount structure in kernel space, 663 * read it in and return a usable pointer to it. 664 */ 665 struct mount * 666 getmnt(maddr) 667 struct mount *maddr; 668 { 669 static struct mtab { 670 struct mtab *next; 671 struct mount *maddr; 672 struct mount mount; 673 } *mhead = NULL; 674 struct mtab *mt; 675 676 for (mt = mhead; mt != NULL; mt = mt->next) 677 if (maddr == mt->maddr) 678 return (&mt->mount); 679 if ((mt = malloc(sizeof(struct mtab))) == NULL) 680 err(1, "malloc"); 681 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); 682 mt->maddr = maddr; 683 mt->next = mhead; 684 mhead = mt; 685 return (&mt->mount); 686 } 687 688 void 689 mount_print(mp) 690 struct mount *mp; 691 { 692 int flags; 693 694 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename, 695 ST.f_mntfromname, ST.f_mntonname); 696 if ((flags = mp->mnt_flag) != 0) { 697 int i; 698 const char *sep = " ("; 699 700 for (i = 0; mnt_flags[i].m_flag; i++) { 701 if (flags & mnt_flags[i].m_flag) { 702 (void)printf("%s%s", sep, mnt_flags[i].m_name); 703 flags &= ~mnt_flags[i].m_flag; 704 sep = ","; 705 } 706 } 707 if (flags) 708 (void)printf("%sunknown_flags:%x", sep, flags); 709 (void)printf(")"); 710 } 711 (void)printf("\n"); 712 } 713 714 char * 715 loadvnodes(avnodes) 716 int *avnodes; 717 { 718 int mib[2]; 719 size_t copysize; 720 char *vnodebase; 721 722 if (memf != NULL) { 723 /* 724 * do it by hand 725 */ 726 return (kinfo_vnodes(avnodes)); 727 } 728 mib[0] = CTL_KERN; 729 mib[1] = KERN_VNODE; 730 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) 731 err(1, "sysctl: KERN_VNODE"); 732 if ((vnodebase = malloc(copysize)) == NULL) 733 err(1, "malloc"); 734 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) 735 err(1, "sysctl: KERN_VNODE"); 736 if (copysize % (VPTRSZ + VNODESZ)) 737 errx(1, "vnode size mismatch"); 738 *avnodes = copysize / (VPTRSZ + VNODESZ); 739 740 return (vnodebase); 741 } 742 743 /* 744 * simulate what a running kernel does in in kinfo_vnode 745 */ 746 char * 747 kinfo_vnodes(avnodes) 748 int *avnodes; 749 { 750 struct mntlist mountlist; 751 struct mount *mp, mount; 752 struct vnode *vp, vnode; 753 char *beg, *bp, *ep; 754 int numvnodes; 755 756 KGET(V_NUMV, numvnodes); 757 if ((bp = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL) 758 err(1, "malloc"); 759 beg = bp; 760 ep = bp + (numvnodes + 20) * (VPTRSZ + VNODESZ); 761 KGET(V_MOUNTLIST, mountlist); 762 for (mp = mountlist.cqh_first;; 763 mp = mount.mnt_list.cqe_next) { 764 KGET2(mp, &mount, sizeof(mount), "mount entry"); 765 for (vp = mount.mnt_vnodelist.lh_first; 766 vp != NULL; vp = vnode.v_mntvnodes.le_next) { 767 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 768 if (bp + VPTRSZ + VNODESZ > ep) 769 /* XXX - should realloc */ 770 errx(1, "no more room for vnodes"); 771 memmove(bp, &vp, VPTRSZ); 772 bp += VPTRSZ; 773 memmove(bp, &vnode, VNODESZ); 774 bp += VNODESZ; 775 } 776 if (mp == mountlist.cqh_last) 777 break; 778 } 779 *avnodes = (bp - beg) / (VPTRSZ + VNODESZ); 780 return (beg); 781 } 782 783 void 784 ttymode() 785 { 786 int ntty; 787 struct ttylist_head tty_head; 788 struct tty *tp, tty; 789 790 KGET(TTY_NTTY, ntty); 791 (void)printf("%d terminal device%s\n", ntty, ntty == 1 ? "" : "s"); 792 KGET(TTY_TTYLIST, tty_head); 793 (void)printf( 794 " LINE RAW CAN OUT HWT LWT COL STATE %-*s PGID DISC\n", 795 PTRSTRWIDTH, "SESS"); 796 for (tp = tty_head.tqh_first; tp; tp = tty.tty_link.tqe_next) { 797 KGET2(tp, &tty, sizeof tty, "tty struct"); 798 ttyprt(&tty); 799 } 800 } 801 802 const struct flagbit_desc ttystates[] = { 803 { TS_ISOPEN, 'O'}, 804 { TS_DIALOUT, '>'}, 805 { TS_CARR_ON, 'C'}, 806 { TS_TIMEOUT, 'T'}, 807 { TS_FLUSH, 'F'}, 808 { TS_BUSY, 'B'}, 809 { TS_ASLEEP, 'A'}, 810 { TS_XCLUDE, 'X'}, 811 { TS_TTSTOP, 'S'}, 812 { TS_TBLOCK, 'K'}, 813 { TS_ASYNC, 'Y'}, 814 { TS_BKSL, 'D'}, 815 { TS_ERASE, 'E'}, 816 { TS_LNCH, 'L'}, 817 { TS_TYPEN, 'P'}, 818 { TS_CNTTB, 'N'}, 819 { 0, '\0'}, 820 }; 821 822 void 823 ttyprt(tp) 824 struct tty *tp; 825 { 826 char state[sizeof(ttystates) / sizeof(ttystates[0]) + 1]; 827 char dev[2 + 3 + 1 + 5 + 1]; /* 12bit major + 20bit minor */ 828 struct linesw t_linesw; 829 char *name, buffer; 830 pid_t pgid; 831 int n, ovflw; 832 833 if (usenumflag || (name = devname(tp->t_dev, S_IFCHR)) == NULL) { 834 (void)snprintf(dev, sizeof(dev), "0x%3x:%x", 835 major(tp->t_dev), minor(tp->t_dev)); 836 name = dev; 837 } 838 ovflw = 0; 839 PRWORD(ovflw, "%-*s", 7, 0, name); 840 PRWORD(ovflw, " %*d", 3, 1, tp->t_rawq.c_cc); 841 PRWORD(ovflw, " %*d", 4, 1, tp->t_canq.c_cc); 842 PRWORD(ovflw, " %*d", 4, 1, tp->t_outq.c_cc); 843 PRWORD(ovflw, " %*d", 5, 1, tp->t_hiwat); 844 PRWORD(ovflw, " %*d", 4, 1, tp->t_lowat); 845 PRWORD(ovflw, " %*d", 8, 1, tp->t_column); 846 n = getflags(ttystates, state, tp->t_state); 847 if (tp->t_wopen) { 848 state[n++] = 'W'; 849 state[n] = '\0'; 850 } 851 PRWORD(ovflw, " %-*s", 7, 1, state); 852 PRWORD(ovflw, " %*lX", PTRSTRWIDTH + 1, 1, (u_long)tp->t_session); 853 pgid = 0; 854 if (tp->t_pgrp != NULL) 855 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); 856 PRWORD(ovflw, " %*d", 6, 1, pgid); 857 KGET2(tp->t_linesw, &t_linesw, sizeof(t_linesw), 858 "line discipline switch table"); 859 name = t_linesw.l_name; 860 (void)putchar(' '); 861 for (;;) { 862 KGET2(name, &buffer, sizeof(buffer), "line discipline name"); 863 if (buffer == '\0') 864 break; 865 (void)putchar(buffer); 866 name++; 867 } 868 (void)putchar('\n'); 869 } 870 871 const struct flagbit_desc filemode_flags[] = { 872 { FREAD, 'R' }, 873 { FWRITE, 'W' }, 874 { FAPPEND, 'A' }, 875 #ifdef FSHLOCK /* currently gone */ 876 { FSHLOCK, 'S' }, 877 { FEXLOCK, 'X' }, 878 #endif 879 { FASYNC, 'I' }, 880 { 0, '\0' }, 881 }; 882 883 void 884 filemode() 885 { 886 struct file *fp; 887 struct file *addr; 888 char flags[sizeof(filemode_flags) / sizeof(filemode_flags[0])]; 889 char *buf; 890 int len, maxfile, nfile, ovflw; 891 static char *dtypes[] = { "???", "inode", "socket" }; 892 893 KGET(FNL_MAXFILE, maxfile); 894 if (totalflag) { 895 KGET(FNL_NFILE, nfile); 896 (void)printf("%3d/%3d files\n", nfile, maxfile); 897 return; 898 } 899 if (getfiles(&buf, &len) == -1) 900 return; 901 /* 902 * Getfiles returns in malloc'd memory a pointer to the first file 903 * structure, and then an array of file structs (whose addresses are 904 * derivable from the previous entry). 905 */ 906 addr = ((struct filelist *)buf)->lh_first; 907 fp = (struct file *)(buf + sizeof(struct filelist)); 908 nfile = (len - sizeof(struct filelist)) / sizeof(struct file); 909 910 (void)printf("%d/%d open files\n", nfile, maxfile); 911 (void)printf("%*s%s%*s TYPE FLG CNT MSG %*s%s%*s OFFSET\n", 912 (PTRSTRWIDTH - 4) / 2, "", " LOC", (PTRSTRWIDTH - 4) / 2, "", 913 (PTRSTRWIDTH - 4) / 2, "", "DATA", (PTRSTRWIDTH - 4) / 2, ""); 914 for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) { 915 if ((unsigned)fp->f_type > DTYPE_SOCKET) 916 continue; 917 ovflw = 0; 918 (void)getflags(filemode_flags, flags, fp->f_flag); 919 PRWORD(ovflw, "%*lx", PTRSTRWIDTH, 0, (long)addr); 920 PRWORD(ovflw, " %-*s", 9, 1, dtypes[fp->f_type]); 921 PRWORD(ovflw, " %*s", 6, 1, flags); 922 PRWORD(ovflw, " %*d", 5, 1, fp->f_count); 923 PRWORD(ovflw, " %*d", 5, 1, fp->f_msgcount); 924 PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 2, (long)fp->f_data); 925 if (fp->f_offset < 0) 926 PRWORD(ovflw, " %-*llx\n", PTRSTRWIDTH + 1, 2, 927 (long long)fp->f_offset); 928 else 929 PRWORD(ovflw, " %-*lld\n", PTRSTRWIDTH + 1, 2, 930 (long long)fp->f_offset); 931 } 932 free(buf); 933 } 934 935 int 936 getfiles(abuf, alen) 937 char **abuf; 938 int *alen; 939 { 940 size_t len; 941 int mib[2]; 942 char *buf; 943 944 /* 945 * XXX 946 * Add emulation of KINFO_FILE here. 947 */ 948 if (memf != NULL) 949 errx(1, "files on dead kernel, not implemented"); 950 951 mib[0] = CTL_KERN; 952 mib[1] = KERN_FILE; 953 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 954 warn("sysctl: KERN_FILE"); 955 return (-1); 956 } 957 if ((buf = malloc(len)) == NULL) 958 err(1, "malloc"); 959 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 960 warn("sysctl: KERN_FILE"); 961 return (-1); 962 } 963 *abuf = buf; 964 *alen = len; 965 return (0); 966 } 967 968 void 969 usage() 970 { 971 972 (void)fprintf(stderr, 973 "usage: %s [-T|-f|-s|-t|-v] [-kn] [-M core] [-N system]\n", 974 getprogname()); 975 exit(1); 976 } 977