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