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