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