pstat.c revision 75854
1/*- 2 * Copyright (c) 1980, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95"; 43#endif 44static const char rcsid[] = 45 "$FreeBSD: head/usr.sbin/pstat/pstat.c 75854 2001-04-23 08:13:18Z grog $"; 46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/time.h> 50#include <sys/vnode.h> 51#include <sys/ucred.h> 52#define _KERNEL 53#include <sys/file.h> 54#include <ufs/ufs/quota.h> 55#include <ufs/ufs/inode.h> 56#include <net/radix.h> 57#include <sys/socket.h> 58#include <sys/mount.h> 59#include <sys/uio.h> 60#include <sys/namei.h> 61#include <miscfs/union/union.h> 62#undef _KERNEL 63#include <sys/stat.h> 64#include <nfs/rpcv2.h> 65#include <nfs/nfsproto.h> 66#include <nfs/nfs.h> 67#include <nfs/nfsnode.h> 68#include <sys/ioctl.h> 69#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */ 70#include <sys/tty.h> 71#include <sys/conf.h> 72#include <sys/blist.h> 73 74#include <sys/user.h> 75#include <sys/sysctl.h> 76 77#include <err.h> 78#include <fcntl.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 87struct nlist nl[] = { 88#define NLMANDATORYBEG 0 89#define V_MOUNTLIST 0 90 { "_mountlist" }, /* address of head of mount list. */ 91#define V_NUMV 1 92 { "_numvnodes" }, 93#define FNL_NFILE 2 94 {"_nfiles"}, 95#define FNL_MAXFILE 3 96 {"_maxfiles"}, 97#define NLMANDATORYEND FNL_MAXFILE /* names up to here are mandatory */ 98#define SCONS NLMANDATORYEND + 1 99 { "_cons" }, 100#define SPTY NLMANDATORYEND + 2 101 { "_pt_tty" }, 102#define SNPTY NLMANDATORYEND + 3 103 { "_npty" }, 104 105 106 107#ifdef __FreeBSD__ 108#define SCCONS (SNPTY+1) 109 { "_sccons" }, 110#define NSCCONS (SNPTY+2) 111 { "_nsccons" }, 112#define SIO (SNPTY+3) 113 { "_sio_tty" }, 114#define NSIO (SNPTY+4) 115 { "_nsio_tty" }, 116#define RC (SNPTY+5) 117 { "_rc_tty" }, 118#define NRC (SNPTY+6) 119 { "_nrc_tty" }, 120#define CY (SNPTY+7) 121 { "_cy_tty" }, 122#define NCY (SNPTY+8) 123 { "_ncy_tty" }, 124#define SI (SNPTY+9) 125 { "_si_tty" }, 126#define NSI (SNPTY+10) 127 { "_si_Nports" }, 128#endif 129 { "" } 130}; 131 132int usenumflag; 133int totalflag; 134int swapflag; 135char *nlistf = NULL; 136char *memf = NULL; 137kvm_t *kd; 138 139char *usagestr; 140 141struct { 142 int m_flag; 143 const char *m_name; 144} mnt_flags[] = { 145 { MNT_RDONLY, "rdonly" }, 146 { MNT_SYNCHRONOUS, "sync" }, 147 { MNT_NOEXEC, "noexec" }, 148 { MNT_NOSUID, "nosuid" }, 149 { MNT_NODEV, "nodev" }, 150 { MNT_UNION, "union" }, 151 { MNT_ASYNC, "async" }, 152 { MNT_SUIDDIR, "suiddir" }, 153 { MNT_SOFTDEP, "softdep" }, 154 { MNT_NOSYMFOLLOW, "nosymfollow" }, 155 { MNT_NOATIME, "noatime" }, 156 { MNT_NOCLUSTERR, "noclusterread" }, 157 { MNT_NOCLUSTERW, "noclusterwrite" }, 158 { MNT_EXRDONLY, "exrdonly" }, 159 { MNT_EXPORTED, "exported" }, 160 { MNT_DEFEXPORTED, "defexported" }, 161 { MNT_EXPORTANON, "exportanon" }, 162 { MNT_EXKERB, "exkerb" }, 163 { MNT_EXPUBLIC, "public" }, 164 { MNT_LOCAL, "local" }, 165 { MNT_QUOTA, "quota" }, 166 { MNT_ROOTFS, "rootfs" }, 167 { MNT_USER, "user" }, 168 { MNT_IGNORE, "ignore" }, 169 { MNT_UPDATE, "update" }, 170 { MNT_DELEXPORT, "delexport" }, 171 { MNT_RELOAD, "reload" }, 172 { MNT_FORCE, "force" }, 173 { MNT_SNAPSHOT, "snapshot" }, 174 { 0 } 175}; 176 177 178#define SVAR(var) __STRING(var) /* to force expansion */ 179#define KGET(idx, var) \ 180 KGET1(idx, &var, sizeof(var), SVAR(var)) 181#define KGET1(idx, p, s, msg) \ 182 KGET2(nl[idx].n_value, p, s, msg) 183#define KGET2(addr, p, s, msg) \ 184 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 185 warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 186#define KGETN(idx, var) \ 187 KGET1N(idx, &var, sizeof(var), SVAR(var)) 188#define KGET1N(idx, p, s, msg) \ 189 KGET2N(nl[idx].n_value, p, s, msg) 190#define KGET2N(addr, p, s, msg) \ 191 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) 192#define KGETRET(addr, p, s, msg) \ 193 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 194 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 195 return (0); \ 196 } 197 198void filemode __P((void)); 199int getfiles __P((char **, int *)); 200struct mount * 201 getmnt __P((struct mount *)); 202struct e_vnode * 203 kinfo_vnodes __P((int *)); 204struct e_vnode * 205 loadvnodes __P((int *)); 206void mount_print __P((struct mount *)); 207void nfs_header __P((void)); 208int nfs_print __P((struct vnode *)); 209void swapmode __P((void)); 210void ttymode __P((void)); 211void ttyprt __P((struct tty *, int)); 212void ttytype __P((struct tty *, char *, int, int, int)); 213void ufs_header __P((void)); 214int ufs_print __P((struct vnode *)); 215void union_header __P((void)); 216int union_print __P((struct vnode *)); 217static void usage __P((void)); 218void vnode_header __P((void)); 219void vnode_print __P((struct vnode *, struct vnode *)); 220void vnodemode __P((void)); 221 222int 223main(argc, argv) 224 int argc; 225 char *argv[]; 226{ 227 int ch, i, quit, ret; 228 int fileflag, ttyflag, vnodeflag; 229 char buf[_POSIX2_LINE_MAX],*opts; 230 231 fileflag = swapflag = ttyflag = vnodeflag = 0; 232 233 /* We will behave like good old swapinfo if thus invoked */ 234 opts = strrchr(argv[0],'/'); 235 if (opts) 236 opts++; 237 else 238 opts = argv[0]; 239 if (!strcmp(opts,"swapinfo")) { 240 swapflag = 1; 241 opts = "kM:N:"; 242 usagestr = "swapinfo [-k] [-M core] [-N system]"; 243 } else { 244 opts = "TM:N:fiknstv"; 245 usagestr = "pstat [-Tfknstv] [-M core] [-N system]"; 246 } 247 248 while ((ch = getopt(argc, argv, opts)) != -1) 249 switch (ch) { 250 case 'f': 251 fileflag = 1; 252 break; 253 case 'k': 254 putenv("BLOCKSIZE=1K"); 255 break; 256 case 'M': 257 memf = optarg; 258 break; 259 case 'N': 260 nlistf = optarg; 261 break; 262 case 'n': 263 usenumflag = 1; 264 break; 265 case 's': 266 ++swapflag; 267 break; 268 case 'T': 269 totalflag = 1; 270 break; 271 case 't': 272 ttyflag = 1; 273 break; 274 case 'v': 275 case 'i': /* Backward compatibility. */ 276 errx(1, "vnode mode not supported"); 277#if 0 278 vnodeflag = 1; 279 break; 280#endif 281 default: 282 usage(); 283 } 284 argc -= optind; 285 argv += optind; 286 287 /* 288 * Discard setgid privileges if not the running kernel so that bad 289 * guys can't print interesting stuff from kernel memory. 290 */ 291 if (nlistf != NULL || memf != NULL) 292 (void)setgid(getgid()); 293 294 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 295 errx(1, "kvm_openfiles: %s", buf); 296 if ((ret = kvm_nlist(kd, nl)) != 0) { 297 if (ret == -1) 298 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 299 for (i = NLMANDATORYBEG, quit = 0; i <= NLMANDATORYEND; i++) 300 if (!nl[i].n_value) { 301 quit = 1; 302 warnx("undefined symbol: %s", nl[i].n_name); 303 } 304 if (quit) 305 exit(1); 306 } 307 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) 308 usage(); 309 if (fileflag || totalflag) 310 filemode(); 311 if (vnodeflag) 312 vnodemode(); 313 if (ttyflag) 314 ttymode(); 315 if (swapflag || totalflag) 316 swapmode(); 317 exit (0); 318} 319 320static void 321usage() 322{ 323 fprintf(stderr, "usage: %s\n", usagestr); 324 exit (1); 325} 326 327struct e_vnode { 328 struct vnode *avnode; 329 struct vnode vnode; 330}; 331 332void 333vnodemode() 334{ 335 struct e_vnode *e_vnodebase, *endvnode, *evp; 336 struct vnode *vp; 337 struct mount *maddr, *mp; 338 int numvnodes; 339 340 e_vnodebase = loadvnodes(&numvnodes); 341 if (totalflag) { 342 (void)printf("%7d vnodes\n", numvnodes); 343 return; 344 } 345 endvnode = e_vnodebase + numvnodes; 346 (void)printf("%d active vnodes\n", numvnodes); 347 348 349#define ST mp->mnt_stat 350 maddr = NULL; 351 for (evp = e_vnodebase; evp < endvnode; evp++) { 352 vp = &evp->vnode; 353 if (vp->v_mount != maddr) { 354 /* 355 * New filesystem 356 */ 357 if ((mp = getmnt(vp->v_mount)) == NULL) 358 continue; 359 maddr = vp->v_mount; 360 mount_print(mp); 361 vnode_header(); 362 if (!strcmp(ST.f_fstypename, "ufs") || 363 !strcmp(ST.f_fstypename, "mfs")) 364 ufs_header(); 365 else if (!strcmp(ST.f_fstypename, "nfs")) 366 nfs_header(); 367 else if (!strcmp(ST.f_fstypename, "union")) 368 union_header(); 369 (void)printf("\n"); 370 } 371 vnode_print(evp->avnode, vp); 372 if (!strcmp(ST.f_fstypename, "ufs") || 373 !strcmp(ST.f_fstypename, "mfs")) 374 ufs_print(vp); 375 else if (!strcmp(ST.f_fstypename, "nfs")) 376 nfs_print(vp); 377 else if (!strcmp(ST.f_fstypename, "union")) 378 union_print(vp); 379 (void)printf("\n"); 380 } 381 free(e_vnodebase); 382} 383 384void 385vnode_header() 386{ 387 (void)printf("ADDR TYP VFLAG USE HOLD"); 388} 389 390void 391vnode_print(avnode, vp) 392 struct vnode *avnode; 393 struct vnode *vp; 394{ 395 char *type, flags[16]; 396 char *fp = flags; 397 int flag; 398 399 /* 400 * set type 401 */ 402 switch (vp->v_type) { 403 case VNON: 404 type = "non"; break; 405 case VREG: 406 type = "reg"; break; 407 case VDIR: 408 type = "dir"; break; 409 case VBLK: 410 type = "blk"; break; 411 case VCHR: 412 type = "chr"; break; 413 case VLNK: 414 type = "lnk"; break; 415 case VSOCK: 416 type = "soc"; break; 417 case VFIFO: 418 type = "fif"; break; 419 case VBAD: 420 type = "bad"; break; 421 default: 422 type = "unk"; break; 423 } 424 /* 425 * gather flags 426 */ 427 flag = vp->v_flag; 428 if (flag & VROOT) 429 *fp++ = 'R'; 430 if (flag & VTEXT) 431 *fp++ = 'T'; 432 if (flag & VSYSTEM) 433 *fp++ = 'S'; 434 if (flag & VISTTY) 435 *fp++ = 't'; 436 if (flag & VXLOCK) 437 *fp++ = 'L'; 438 if (flag & VXWANT) 439 *fp++ = 'W'; 440 if (flag & VBWAIT) 441 *fp++ = 'B'; 442 if (flag & VOBJBUF) 443 *fp++ = 'V'; 444 if (flag & VCOPYONWRITE) 445 *fp++ = 'C'; 446 if (flag & VAGE) 447 *fp++ = 'a'; 448 if (flag & VOLOCK) 449 *fp++ = 'l'; 450 if (flag & VOWANT) 451 *fp++ = 'w'; 452 if (flag & VDOOMED) 453 *fp++ = 'D'; 454 if (flag & VFREE) 455 *fp++ = 'F'; 456 if (flag & VONWORKLST) 457 *fp++ = 'O'; 458 if (flag & VMOUNT) 459 *fp++ = 'M'; 460 461 if (flag == 0) 462 *fp++ = '-'; 463 *fp = '\0'; 464 (void)printf("%8lx %s %5s %4d %4d", 465 (u_long)(void *)avnode, type, flags, vp->v_usecount, vp->v_holdcnt); 466} 467 468void 469ufs_header() 470{ 471 (void)printf(" FILEID IFLAG RDEV|SZ"); 472} 473 474int 475ufs_print(vp) 476 struct vnode *vp; 477{ 478 int flag; 479 struct inode inode, *ip = &inode; 480 char flagbuf[16], *flags = flagbuf; 481 char *name; 482 mode_t type; 483 484 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 485 flag = ip->i_flag; 486 if (flag & IN_ACCESS) 487 *flags++ = 'A'; 488 if (flag & IN_CHANGE) 489 *flags++ = 'C'; 490 if (flag & IN_UPDATE) 491 *flags++ = 'U'; 492 if (flag & IN_MODIFIED) 493 *flags++ = 'M'; 494 if (flag & IN_RENAME) 495 *flags++ = 'R'; 496 if (flag & IN_SHLOCK) 497 *flags++ = 'S'; 498 if (flag & IN_EXLOCK) 499 *flags++ = 'E'; 500 if (flag & IN_HASHED) 501 *flags++ = 'H'; 502 if (flag & IN_LAZYMOD) 503 *flags++ = 'L'; 504 if (flag == 0) 505 *flags++ = '-'; 506 *flags = '\0'; 507 508 (void)printf(" %6d %5s", ip->i_number, flagbuf); 509 type = ip->i_mode & S_IFMT; 510 if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) 511 if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL)) 512 (void)printf(" %2d,%-2d", 513 major(ip->i_rdev), minor(ip->i_rdev)); 514 else 515 (void)printf(" %7s", name); 516 else 517 (void)printf(" %7qd", ip->i_size); 518 return (0); 519} 520 521void 522nfs_header() 523{ 524 (void)printf(" FILEID NFLAG RDEV|SZ"); 525} 526 527int 528nfs_print(vp) 529 struct vnode *vp; 530{ 531 struct nfsnode nfsnode, *np = &nfsnode; 532 char flagbuf[16], *flags = flagbuf; 533 int flag; 534 char *name; 535 mode_t type; 536 537 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); 538 flag = np->n_flag; 539 if (flag & NFLUSHWANT) 540 *flags++ = 'W'; 541 if (flag & NFLUSHINPROG) 542 *flags++ = 'P'; 543 if (flag & NMODIFIED) 544 *flags++ = 'M'; 545 if (flag & NWRITEERR) 546 *flags++ = 'E'; 547 if (flag & NQNFSNONCACHE) 548 *flags++ = 'X'; 549 if (flag & NQNFSWRITE) 550 *flags++ = 'O'; 551 if (flag & NQNFSEVICTED) 552 *flags++ = 'G'; 553 if (flag & NACC) 554 *flags++ = 'A'; 555 if (flag & NUPD) 556 *flags++ = 'U'; 557 if (flag & NCHG) 558 *flags++ = 'C'; 559 if (flag & NLOCKED) 560 *flags++ = 'L'; 561 if (flag & NWANTED) 562 *flags++ = 'w'; 563 if (flag == 0) 564 *flags++ = '-'; 565 *flags = '\0'; 566 567#define VT np->n_vattr 568 (void)printf(" %6ld %5s", VT.va_fileid, flagbuf); 569 type = VT.va_mode & S_IFMT; 570 if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode)) 571 if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL)) 572 (void)printf(" %2d,%-2d", 573 major(VT.va_rdev), minor(VT.va_rdev)); 574 else 575 (void)printf(" %7s", name); 576 else 577 (void)printf(" %7qd", np->n_size); 578 return (0); 579} 580 581void 582union_header() 583{ 584 (void)printf(" UPPER LOWER"); 585} 586 587int 588union_print(vp) 589 struct vnode *vp; 590{ 591 struct union_node unode, *up = &unode; 592 593 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode"); 594 595 (void)printf(" %8lx %8lx", (u_long)(void *)up->un_uppervp, 596 (u_long)(void *)up->un_lowervp); 597 return (0); 598} 599 600/* 601 * Given a pointer to a mount structure in kernel space, 602 * read it in and return a usable pointer to it. 603 */ 604struct mount * 605getmnt(maddr) 606 struct mount *maddr; 607{ 608 static struct mtab { 609 struct mtab *next; 610 struct mount *maddr; 611 struct mount mount; 612 } *mhead = NULL; 613 struct mtab *mt; 614 615 for (mt = mhead; mt != NULL; mt = mt->next) 616 if (maddr == mt->maddr) 617 return (&mt->mount); 618 if ((mt = malloc(sizeof(struct mtab))) == NULL) 619 errx(1, "malloc"); 620 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); 621 mt->maddr = maddr; 622 mt->next = mhead; 623 mhead = mt; 624 return (&mt->mount); 625} 626 627void 628mount_print(mp) 629 struct mount *mp; 630{ 631 int flags; 632 const char *type; 633 634#define ST mp->mnt_stat 635 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename, 636 ST.f_mntfromname, ST.f_mntonname); 637 if ((flags = mp->mnt_flag)) { 638 int i; 639 const char *sep = " ("; 640 641 for (i = 0; mnt_flags[i].m_flag; i++) { 642 if (flags & mnt_flags[i].m_flag) { 643 (void)printf("%s%s", sep, mnt_flags[i].m_name); 644 flags &= ~mnt_flags[i].m_flag; 645 sep = ","; 646 } 647 } 648 if (flags) 649 (void)printf("%sunknown_flags:%x", sep, flags); 650 (void)printf(")"); 651 } 652 (void)printf("\n"); 653#undef ST 654} 655 656struct e_vnode * 657loadvnodes(avnodes) 658 int *avnodes; 659{ 660 int mib[2]; 661 size_t copysize; 662 struct e_vnode *vnodebase; 663 664 if (memf != NULL) { 665 /* 666 * do it by hand 667 */ 668 return (kinfo_vnodes(avnodes)); 669 } 670 mib[0] = CTL_KERN; 671 mib[1] = KERN_VNODE; 672 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) 673 err(1, "sysctl: KERN_VNODE"); 674 if ((vnodebase = malloc(copysize)) == NULL) 675 errx(1, "malloc"); 676 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) 677 err(1, "sysctl: KERN_VNODE"); 678 if (copysize % sizeof(struct e_vnode)) 679 errx(1, "vnode size mismatch"); 680 *avnodes = copysize / sizeof(struct e_vnode); 681 682 return (vnodebase); 683} 684 685/* 686 * simulate what a running kernel does in in kinfo_vnode 687 */ 688struct e_vnode * 689kinfo_vnodes(avnodes) 690 int *avnodes; 691{ 692 struct mntlist mountlist; 693 struct mount *mp, mount, *mp_next; 694 struct vnode *vp, vnode, *vp_next; 695 char *vbuf, *evbuf, *bp; 696 int num, numvnodes; 697 698#define VPTRSZ sizeof(struct vnode *) 699#define VNODESZ sizeof(struct vnode) 700 701 KGET(V_NUMV, numvnodes); 702 if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL) 703 errx(1, "malloc"); 704 bp = vbuf; 705 evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ); 706 KGET(V_MOUNTLIST, mountlist); 707 for (num = 0, mp = TAILQ_FIRST(&mountlist); ; mp = mp_next) { 708 KGET2(mp, &mount, sizeof(mount), "mount entry"); 709 mp_next = TAILQ_NEXT(&mount, mnt_list); 710 for (vp = LIST_FIRST(&mount.mnt_vnodelist); 711 vp != NULL; vp = vp_next) { 712 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 713 vp_next = LIST_NEXT(&vnode, v_mntvnodes); 714 if ((bp + VPTRSZ + VNODESZ) > evbuf) 715 /* XXX - should realloc */ 716 errx(1, "no more room for vnodes"); 717 memmove(bp, &vp, VPTRSZ); 718 bp += VPTRSZ; 719 memmove(bp, &vnode, VNODESZ); 720 bp += VNODESZ; 721 num++; 722 } 723 if (mp == TAILQ_LAST(&mountlist, mntlist)) 724 break; 725 } 726 *avnodes = num; 727 return ((struct e_vnode *)vbuf); 728} 729 730const char hdr[] = 731" LINE RAW CAN OUT IHIWT ILOWT OHWT LWT COL STATE SESS PGID DISC\n"; 732int ttyspace = 128; 733 734void 735ttymode() 736{ 737 struct tty *tty; 738 struct tty ttyb[1000]; 739 int error, len, i; 740 741 (void)printf(hdr); 742 len = sizeof(ttyb); 743 error = sysctlbyname("kern.ttys", &ttyb, &len, 0, 0); 744 if (!error) { 745 len /= sizeof(ttyb[0]); 746 for (i = 0; i < len; i++) { 747 ttyprt(&ttyb[i], 0); 748 } 749 } 750 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL) 751 errx(1, "malloc"); 752 if (nl[SCONS].n_type != 0) { 753 (void)printf("1 console\n"); 754 KGET(SCONS, *tty); 755 ttyprt(&tty[0], 0); 756 } 757#ifdef __FreeBSD__ 758 if (nl[NSCCONS].n_type != 0) 759 ttytype(tty, "vty", SCCONS, NSCCONS, 0); 760 if (nl[NSIO].n_type != 0) 761 ttytype(tty, "sio", SIO, NSIO, 0); 762 if (nl[NRC].n_type != 0) 763 ttytype(tty, "rc", RC, NRC, 0); 764 if (nl[NCY].n_type != 0) 765 ttytype(tty, "cy", CY, NCY, 0); 766 if (nl[NSI].n_type != 0) 767 ttytype(tty, "si", SI, NSI, 1); 768#endif 769 if (nl[SNPTY].n_type != 0) 770 ttytype(tty, "pty", SPTY, SNPTY, 0); 771} 772 773void 774ttytype(tty, name, type, number, indir) 775 struct tty *tty; 776 char *name; 777 int type, number, indir; 778{ 779 struct tty *tp; 780 int ntty; 781 struct tty **ttyaddr; 782 783 if (tty == NULL) 784 return; 785 KGET(number, ntty); 786 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines"); 787 if (ntty > ttyspace) { 788 ttyspace = ntty; 789 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0) 790 errx(1, "realloc"); 791 } 792 if (indir) { 793 KGET(type, ttyaddr); 794 KGET2(ttyaddr, tty, ntty * sizeof(struct tty), "tty structs"); 795 } else { 796 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs"); 797 } 798 (void)printf(hdr); 799 for (tp = tty; tp < &tty[ntty]; tp++) 800 ttyprt(tp, tp - tty); 801} 802 803struct { 804 int flag; 805 char val; 806} ttystates[] = { 807#ifdef TS_WOPEN 808 { TS_WOPEN, 'W'}, 809#endif 810 { TS_ISOPEN, 'O'}, 811 { TS_CARR_ON, 'C'}, 812#ifdef TS_CONNECTED 813 { TS_CONNECTED, 'c'}, 814#endif 815 { TS_TIMEOUT, 'T'}, 816 { TS_FLUSH, 'F'}, 817 { TS_BUSY, 'B'}, 818#ifdef TS_ASLEEP 819 { TS_ASLEEP, 'A'}, 820#endif 821#ifdef TS_SO_OLOWAT 822 { TS_SO_OLOWAT, 'A'}, 823#endif 824#ifdef TS_SO_OCOMPLETE 825 { TS_SO_OCOMPLETE, 'a'}, 826#endif 827 { TS_XCLUDE, 'X'}, 828 { TS_TTSTOP, 'S'}, 829#ifdef TS_CAR_OFLOW 830 { TS_CAR_OFLOW, 'm'}, 831#endif 832#ifdef TS_CTS_OFLOW 833 { TS_CTS_OFLOW, 'o'}, 834#endif 835#ifdef TS_DSR_OFLOW 836 { TS_DSR_OFLOW, 'd'}, 837#endif 838 { TS_TBLOCK, 'K'}, 839 { TS_ASYNC, 'Y'}, 840 { TS_BKSL, 'D'}, 841 { TS_ERASE, 'E'}, 842 { TS_LNCH, 'L'}, 843 { TS_TYPEN, 'P'}, 844 { TS_CNTTB, 'N'}, 845#ifdef TS_CAN_BYPASS_L_RINT 846 { TS_CAN_BYPASS_L_RINT, 'l'}, 847#endif 848#ifdef TS_SNOOP 849 { TS_SNOOP, 's'}, 850#endif 851#ifdef TS_ZOMBIE 852 { TS_ZOMBIE, 'Z'}, 853#endif 854 { 0, '\0'}, 855}; 856 857void 858ttyprt(tp, line) 859 struct tty *tp; 860 int line; 861{ 862 int i, j; 863 pid_t pgid; 864 char *name, state[20]; 865 866 if (usenumflag || tp->t_dev == 0 || 867 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 868 (void)printf("%7d ", line); 869 else 870 (void)printf("%7s ", name); 871 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 872 (void)printf("%3d %5d %5d %4d %3d %7d ", tp->t_outq.c_cc, 873 tp->t_ihiwat, tp->t_ilowat, tp->t_ohiwat, tp->t_olowat, 874 tp->t_column); 875 for (i = j = 0; ttystates[i].flag; i++) 876 if (tp->t_state&ttystates[i].flag) 877 state[j++] = ttystates[i].val; 878 if (j == 0) 879 state[j++] = '-'; 880 state[j] = '\0'; 881 (void)printf("%-6s %8lx", state, (u_long)(void *)tp->t_session); 882 pgid = 0; 883 if (tp->t_pgrp != NULL) 884 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); 885 (void)printf("%6d ", pgid); 886 switch (tp->t_line) { 887 case TTYDISC: 888 (void)printf("term\n"); 889 break; 890 case NTTYDISC: 891 (void)printf("ntty\n"); 892 break; 893 case SLIPDISC: 894 (void)printf("slip\n"); 895 break; 896 case PPPDISC: 897 (void)printf("ppp\n"); 898 break; 899 default: 900 (void)printf("%d\n", tp->t_line); 901 break; 902 } 903} 904 905void 906filemode() 907{ 908 struct file *fp; 909 struct file *addr; 910 char *buf, flagbuf[16], *fbp; 911 int len, maxfile, nfile; 912 static char *dtypes[] = { "???", "inode", "socket" }; 913 914 KGET(FNL_MAXFILE, maxfile); 915 if (totalflag) { 916 KGET(FNL_NFILE, nfile); 917 (void)printf("%3d/%3d files\n", nfile, maxfile); 918 return; 919 } 920 if (getfiles(&buf, &len) == -1) 921 return; 922 /* 923 * Getfiles returns in malloc'd memory a pointer to the first file 924 * structure, and then an array of file structs (whose addresses are 925 * derivable from the previous entry). 926 */ 927 addr = LIST_FIRST((struct filelist *)buf); 928 fp = (struct file *)(buf + sizeof(struct filelist)); 929 nfile = (len - sizeof(struct filelist)) / sizeof(struct file); 930 931 (void)printf("%d/%d open files\n", nfile, maxfile); 932 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 933 for (; (char *)fp < buf + len; addr = LIST_NEXT(fp, f_list), fp++) { 934 if ((unsigned)fp->f_type > DTYPE_SOCKET) 935 continue; 936 (void)printf("%8lx ", (u_long)(void *)addr); 937 (void)printf("%-8.8s", dtypes[fp->f_type]); 938 fbp = flagbuf; 939 if (fp->f_flag & FREAD) 940 *fbp++ = 'R'; 941 if (fp->f_flag & FWRITE) 942 *fbp++ = 'W'; 943 if (fp->f_flag & FAPPEND) 944 *fbp++ = 'A'; 945#ifdef FSHLOCK /* currently gone */ 946 if (fp->f_flag & FSHLOCK) 947 *fbp++ = 'S'; 948 if (fp->f_flag & FEXLOCK) 949 *fbp++ = 'X'; 950#endif 951 if (fp->f_flag & FASYNC) 952 *fbp++ = 'I'; 953 *fbp = '\0'; 954 (void)printf("%6s %3d", flagbuf, fp->f_count); 955 (void)printf(" %3d", fp->f_msgcount); 956 (void)printf(" %8lx", (u_long)(void *)fp->f_data); 957 if (fp->f_offset < 0) 958 (void)printf(" %qx\n", fp->f_offset); 959 else 960 (void)printf(" %qd\n", fp->f_offset); 961 } 962 free(buf); 963} 964 965int 966getfiles(abuf, alen) 967 char **abuf; 968 int *alen; 969{ 970 size_t len; 971 int mib[2]; 972 char *buf; 973 974 /* 975 * XXX 976 * Add emulation of KINFO_FILE here. 977 */ 978 if (memf != NULL) 979 errx(1, "files on dead kernel, not implemented"); 980 981 mib[0] = CTL_KERN; 982 mib[1] = KERN_FILE; 983 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 984 warn("sysctl: KERN_FILE"); 985 return (-1); 986 } 987 if ((buf = malloc(len)) == NULL) 988 errx(1, "malloc"); 989 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 990 warn("sysctl: KERN_FILE"); 991 return (-1); 992 } 993 *abuf = buf; 994 *alen = len; 995 return (0); 996} 997 998/* 999 * swapmode is based on a program called swapinfo written 1000 * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 1001 */ 1002void 1003swapmode(void) 1004{ 1005 struct kvm_swap kswap[16]; 1006 int i; 1007 int n; 1008 int pagesize = getpagesize(); 1009 const char *header; 1010 int hlen; 1011 long blocksize; 1012 1013 n = kvm_getswapinfo( 1014 kd, 1015 kswap, 1016 sizeof(kswap)/sizeof(kswap[0]), 1017 ((swapflag > 1) ? SWIF_DUMP_TREE : 0) | SWIF_DEV_PREFIX 1018 ); 1019 1020#define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize)) 1021 1022 header = getbsize(&hlen, &blocksize); 1023 if (totalflag == 0) { 1024 (void)printf("%-15s %*s %8s %8s %8s %s\n", 1025 "Device", hlen, header, 1026 "Used", "Avail", "Capacity", "Type"); 1027 1028 for (i = 0; i < n; ++i) { 1029 (void)printf( 1030 "%-15s %*d ", 1031 kswap[i].ksw_devname, 1032 hlen, 1033 CONVERT(kswap[i].ksw_total) 1034 ); 1035 (void)printf( 1036 "%8d %8d %5.0f%% %s\n", 1037 CONVERT(kswap[i].ksw_used), 1038 CONVERT(kswap[i].ksw_total - kswap[i].ksw_used), 1039 (double)kswap[i].ksw_used * 100.0 / 1040 (double)kswap[i].ksw_total, 1041 (kswap[i].ksw_flags & SW_SEQUENTIAL) ? 1042 "Sequential" : "Interleaved" 1043 ); 1044 } 1045 } 1046 1047 if (totalflag) { 1048 blocksize = 1024 * 1024; 1049 1050 (void)printf( 1051 "%dM/%dM swap space\n", 1052 CONVERT(kswap[n].ksw_used), 1053 CONVERT(kswap[n].ksw_total) 1054 ); 1055 } else if (n > 1) { 1056 (void)printf( 1057 "%-15s %*d %8d %8d %5.0f%%\n", 1058 "Total", 1059 hlen, 1060 CONVERT(kswap[n].ksw_total), 1061 CONVERT(kswap[n].ksw_used), 1062 CONVERT(kswap[n].ksw_total - kswap[n].ksw_used), 1063 (double)kswap[n].ksw_used * 100.0 / 1064 (double)kswap[n].ksw_total 1065 ); 1066 } 1067} 1068