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