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