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