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