pstat.c revision 1.76
1/* $OpenBSD: pstat.c,v 1.76 2009/05/31 19:31:23 thib Exp $ */ 2/* $NetBSD: pstat.c,v 1.27 1996/10/23 22:50:06 cgd Exp $ */ 3 4/*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static char copyright[] = 35"@(#) Copyright (c) 1980, 1991, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /* not lint */ 38 39#ifndef lint 40#if 0 41from: static char sccsid[] = "@(#)pstat.c 8.9 (Berkeley) 2/16/94"; 42#else 43static char *rcsid = "$OpenBSD: pstat.c,v 1.76 2009/05/31 19:31:23 thib Exp $"; 44#endif 45#endif /* not lint */ 46 47#include <sys/param.h> 48#include <sys/time.h> 49#include <sys/buf.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#undef _KERNEL 58#include <sys/stat.h> 59#include <nfs/nfsproto.h> 60#include <nfs/rpcv2.h> 61#include <nfs/nfsnode.h> 62#include <sys/ioctl.h> 63#include <sys/tty.h> 64#include <sys/conf.h> 65#include <sys/device.h> 66#include <sys/swap.h> 67 68#include <sys/sysctl.h> 69 70#include <err.h> 71#include <kvm.h> 72#include <limits.h> 73#include <nlist.h> 74#include <paths.h> 75#include <stdio.h> 76#include <stdlib.h> 77#include <string.h> 78#include <unistd.h> 79 80struct nlist vnodenl[] = { 81#define FNL_NFILE 0 /* sysctl */ 82 {"_nfiles"}, 83#define FNL_MAXFILE 1 /* sysctl */ 84 {"_maxfiles"}, 85#define TTY_NTTY 2 /* sysctl */ 86 {"_tty_count"}, 87#define V_NUMV 3 /* sysctl */ 88 { "_numvnodes" }, 89#define TTY_TTYLIST 4 /* sysctl */ 90 {"_ttylist"}, 91#define V_MOUNTLIST 5 /* no sysctl */ 92 { "_mountlist" }, 93 { NULL } 94}; 95 96struct nlist *globalnl; 97 98int usenumflag; 99int totalflag; 100int kflag; 101char *nlistf = NULL; 102char *memf = NULL; 103kvm_t *kd = NULL; 104 105#define SVAR(var) __STRING(var) /* to force expansion */ 106#define KGET(idx, var) \ 107 KGET1(idx, &var, sizeof(var), SVAR(var)) 108#define KGET1(idx, p, s, msg) \ 109 KGET2(globalnl[idx].n_value, p, s, msg) 110#define KGET2(addr, p, s, msg) \ 111 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 112 warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 113#define KGETRET(addr, p, s, msg) \ 114 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 115 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 116 return (0); \ 117 } 118 119void filemode(void); 120int getfiles(char **, size_t *); 121struct mount * 122 getmnt(struct mount *); 123struct e_vnode * 124 kinfo_vnodes(int *); 125struct e_vnode * 126 loadvnodes(int *); 127void mount_print(struct mount *); 128void nfs_header(void); 129int nfs_print(struct vnode *); 130void swapmode(void); 131void ttymode(void); 132void ttyprt(struct itty *); 133void ufs_header(void); 134int ufs_print(struct vnode *); 135void ext2fs_header(void); 136int ext2fs_print(struct vnode *); 137void usage(void); 138void vnode_header(void); 139void vnode_print(struct vnode *, struct vnode *); 140void vnodemode(void); 141 142int 143main(int argc, char *argv[]) 144{ 145 int fileflag = 0, swapflag = 0, ttyflag = 0, vnodeflag = 0, ch; 146 char buf[_POSIX2_LINE_MAX]; 147 const char *dformat = NULL; 148 extern char *optarg; 149 extern int optind; 150 gid_t gid; 151 int i; 152 153 while ((ch = getopt(argc, argv, "d:TM:N:fiknstv")) != -1) 154 switch (ch) { 155 case 'd': 156 dformat = optarg; 157 break; 158 case 'f': 159 fileflag = 1; 160 break; 161 case 'M': 162 memf = optarg; 163 break; 164 case 'N': 165 nlistf = optarg; 166 break; 167 case 'n': 168 usenumflag = 1; 169 break; 170 case 's': 171 swapflag = 1; 172 break; 173 case 'T': 174 totalflag = 1; 175 break; 176 case 't': 177 ttyflag = 1; 178 break; 179 case 'k': 180 kflag = 1; 181 break; 182 case 'v': 183 case 'i': /* Backward compatibility. */ 184 vnodeflag = 1; 185 break; 186 default: 187 usage(); 188 } 189 argc -= optind; 190 argv += optind; 191 192 if (dformat && getuid()) 193 errx(1, "Only root can use -d"); 194 195 if ((dformat == 0 && argc > 0) || (dformat && argc == 0)) 196 usage(); 197 198 /* 199 * Discard setgid privileges if not the running kernel so that bad 200 * guys can't print interesting stuff from kernel memory. 201 */ 202 gid = getgid(); 203 if (nlistf != NULL || memf != NULL) 204 if (setresgid(gid, gid, gid) == -1) 205 err(1, "setresgid"); 206 207 if (vnodeflag || dformat) 208 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 209 errx(1, "kvm_openfiles: %s", buf); 210 211 if (nlistf == NULL && memf == NULL) 212 if (setresgid(gid, gid, gid) == -1) 213 err(1, "setresgid"); 214 if (dformat) { 215 struct nlist *nl; 216 int longformat = 0, stringformat = 0, error = 0, n; 217 int mask = ~0; 218 char format[10], buf[1024]; 219 220 n = strlen(dformat); 221 if (n == 0) 222 errx(1, "illegal format"); 223 224 /* 225 * Support p, c, s, and {l, ll, h, hh, j, t, z, }[diouxX] 226 */ 227 if (strcmp(dformat, "p") == 0) 228 longformat = sizeof(long) == 8; 229 else if (strcmp(dformat, "c") == 0) 230 mask = 0xff; 231 else if (strcmp(dformat, "s") == 0) 232 stringformat = 1; 233 else if (strchr("diouxX", dformat[n - 1])) { 234 char *ptbl[]= {"l", "ll", "h", "hh", "j", "t", "z", ""}; 235 int i; 236 237 char *mod; 238 for (i = 0; i < sizeof(ptbl)/sizeof(ptbl[0]); i++) { 239 mod = ptbl[i]; 240 if (strlen(mod) == n - 1 && 241 strncmp(mod, dformat, strlen(mod)) == 0) 242 break; 243 } 244 if (i == sizeof(ptbl)/sizeof(ptbl[0]) 245 && dformat[1] != '\0') 246 errx(1, "illegal format"); 247 if (strcmp(mod, "l") == 0) 248 longformat = sizeof(long) == sizeof(long long); 249 else if (strcmp(mod, "h") == 0) 250 mask = 0xffff; 251 else if (strcmp(mod, "hh") == 0) 252 mask = 0xff; 253 else 254 longformat = 1; 255 256 } else 257 errx(1, "illegal format"); 258 259 if (*dformat == 's') { 260 stringformat = 1; 261 snprintf(format, sizeof(format), "%%.%zus", 262 sizeof buf); 263 } else 264 snprintf(format, sizeof(format), "%%%s", dformat); 265 266 nl = calloc(argc + 1, sizeof *nl); 267 if (!nl) 268 err(1, "calloc nl: "); 269 for (i = 0; i < argc; i++) { 270 if (asprintf(&nl[i].n_name, "_%s", 271 argv[i]) == -1) 272 warn("asprintf"); 273 } 274 kvm_nlist(kd, nl); 275 globalnl = nl; 276 for (i = 0; i < argc; i++) { 277 long long v; 278 279 printf("%s ", argv[i]); 280 if (!nl[i].n_value && argv[i][0] == '0') { 281 nl[i].n_value = strtoul(argv[i], NULL, 16); 282 nl[i].n_type = N_DATA; 283 } 284 if (!nl[i].n_value) { 285 printf("not found\n"); 286 error++; 287 continue; 288 } 289 290 printf("at %p: ", (void *)nl[i].n_value); 291 if (nl[i].n_type == N_DATA) { 292 if (stringformat) { 293 KGET1(i, &buf, sizeof(buf), argv[i]); 294 buf[sizeof(buf) - 1] = '\0'; 295 } else 296 KGET1(i, &v, sizeof(v), argv[i]); 297 if (stringformat) 298 printf(format, &buf); 299 else if (longformat) 300 printf(format, v); 301 else 302 printf(format, ((int)v) & mask); 303 } 304 printf("\n"); 305 } 306 for (i = 0; i < argc; i++) 307 free(nl[i].n_name); 308 free(nl); 309 exit(error); 310 } 311 312 if (vnodeflag) 313 if (kvm_nlist(kd, vnodenl) == -1) 314 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 315 316 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag || dformat)) 317 usage(); 318 if (fileflag || totalflag) 319 filemode(); 320 if (vnodeflag || totalflag) 321 vnodemode(); 322 if (ttyflag) 323 ttymode(); 324 if (swapflag || totalflag) 325 swapmode(); 326 exit(0); 327} 328 329void 330vnodemode(void) 331{ 332 struct e_vnode *e_vnodebase, *endvnode, *evp; 333 struct vnode *vp; 334 struct mount *maddr, *mp = NULL; 335 int numvnodes; 336 337 globalnl = vnodenl; 338 339 e_vnodebase = loadvnodes(&numvnodes); 340 if (totalflag) { 341 (void)printf("%7d vnodes\n", numvnodes); 342 return; 343 } 344 endvnode = e_vnodebase + numvnodes; 345 (void)printf("%d active vnodes\n", numvnodes); 346 347 maddr = NULL; 348 for (evp = e_vnodebase; evp < endvnode; evp++) { 349 vp = &evp->vnode; 350 if (vp->v_mount != maddr) { 351 /* 352 * New filesystem 353 */ 354 if ((mp = getmnt(vp->v_mount)) == NULL) 355 continue; 356 maddr = vp->v_mount; 357 mount_print(mp); 358 vnode_header(); 359 if (!strncmp(mp->mnt_stat.f_fstypename, MOUNT_FFS, MFSNAMELEN) || 360 !strncmp(mp->mnt_stat.f_fstypename, MOUNT_MFS, MFSNAMELEN)) { 361 ufs_header(); 362 } else if (!strncmp(mp->mnt_stat.f_fstypename, MOUNT_NFS, 363 MFSNAMELEN)) { 364 nfs_header(); 365 } else if (!strncmp(mp->mnt_stat.f_fstypename, MOUNT_EXT2FS, 366 MFSNAMELEN)) { 367 ext2fs_header(); 368 } 369 (void)printf("\n"); 370 } 371 vnode_print(evp->vptr, vp); 372 373 /* Syncer vnodes have no associated fs-specific data */ 374 if (vp->v_data == NULL) { 375 printf(" %6c %5c %7c\n", '-', '-', '-'); 376 continue; 377 } 378 379 if (!strncmp(mp->mnt_stat.f_fstypename, MOUNT_FFS, MFSNAMELEN) || 380 !strncmp(mp->mnt_stat.f_fstypename, MOUNT_MFS, MFSNAMELEN)) { 381 ufs_print(vp); 382 } else if (!strncmp(mp->mnt_stat.f_fstypename, MOUNT_NFS, MFSNAMELEN)) { 383 nfs_print(vp); 384 } else if (!strncmp(mp->mnt_stat.f_fstypename, MOUNT_EXT2FS, 385 MFSNAMELEN)) { 386 ext2fs_print(vp); 387 } 388 (void)printf("\n"); 389 } 390 free(e_vnodebase); 391} 392 393void 394vnode_header(void) 395{ 396 (void)printf("%*s TYP VFLAG USE HOLD", 2 * (int)sizeof(long), "ADDR"); 397} 398 399void 400vnode_print(struct vnode *avnode, struct vnode *vp) 401{ 402 char *type, flags[16]; 403 char *fp = flags; 404 int flag; 405 406 /* 407 * set type 408 */ 409 switch (vp->v_type) { 410 case VNON: 411 type = "non"; break; 412 case VREG: 413 type = "reg"; break; 414 case VDIR: 415 type = "dir"; break; 416 case VBLK: 417 type = "blk"; break; 418 case VCHR: 419 type = "chr"; break; 420 case VLNK: 421 type = "lnk"; break; 422 case VSOCK: 423 type = "soc"; break; 424 case VFIFO: 425 type = "fif"; break; 426 case VBAD: 427 type = "bad"; break; 428 default: 429 type = "unk"; break; 430 } 431 /* 432 * gather flags 433 */ 434 flag = vp->v_flag; 435 if (flag & VROOT) 436 *fp++ = 'R'; 437 if (flag & VTEXT) 438 *fp++ = 'T'; 439 if (flag & VSYSTEM) 440 *fp++ = 'S'; 441 if (flag & VISTTY) 442 *fp++ = 'I'; 443 if (flag & VXLOCK) 444 *fp++ = 'L'; 445 if (flag & VXWANT) 446 *fp++ = 'W'; 447 if (vp->v_bioflag & VBIOWAIT) 448 *fp++ = 'B'; 449 if (flag & VALIASED) 450 *fp++ = 'A'; 451 if (vp->v_bioflag & VBIOONFREELIST) 452 *fp++ = 'F'; 453 if (flag & VLOCKSWORK) 454 *fp++ = 'l'; 455 if (vp->v_bioflag & VBIOONSYNCLIST) 456 *fp++ = 's'; 457 if (flag == 0) 458 *fp++ = '-'; 459 *fp = '\0'; 460 (void)printf("%0*lx %s %5s %4d %4u", 2 * (int)sizeof(long), 461 (long)avnode, type, flags, vp->v_usecount, vp->v_holdcnt); 462} 463 464void 465ufs_header(void) 466{ 467 (void)printf(" FILEID IFLAG RDEV|SZ"); 468} 469 470int 471ufs_print(struct vnode *vp) 472{ 473 int flag; 474 struct inode inode, *ip = &inode; 475 struct ufs1_dinode di1; 476 char flagbuf[16], *flags = flagbuf; 477 char *name; 478 mode_t type; 479 480 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 481 KGETRET(inode.i_din1, &di1, sizeof(struct ufs1_dinode), 482 "vnode's dinode"); 483 484 inode.i_din1 = &di1; 485 flag = ip->i_flag; 486#if 0 487 if (flag & IN_LOCKED) 488 *flags++ = 'L'; 489 if (flag & IN_WANTED) 490 *flags++ = 'W'; 491 if (flag & IN_LWAIT) 492 *flags++ = 'Z'; 493#endif 494 if (flag & IN_ACCESS) 495 *flags++ = 'A'; 496 if (flag & IN_CHANGE) 497 *flags++ = 'C'; 498 if (flag & IN_UPDATE) 499 *flags++ = 'U'; 500 if (flag & IN_MODIFIED) 501 *flags++ = 'M'; 502 if (flag & IN_RENAME) 503 *flags++ = 'R'; 504 if (flag & IN_SHLOCK) 505 *flags++ = 'S'; 506 if (flag & IN_EXLOCK) 507 *flags++ = 'E'; 508 if (flag == 0) 509 *flags++ = '-'; 510 *flags = '\0'; 511 512 (void)printf(" %6d %5s", ip->i_number, flagbuf); 513 type = ip->i_ffs1_mode & S_IFMT; 514 if (S_ISCHR(ip->i_ffs1_mode) || S_ISBLK(ip->i_ffs1_mode)) 515 if (usenumflag || 516 ((name = devname(ip->i_ffs1_rdev, type)) == NULL)) 517 (void)printf(" %2d,%-2d", 518 major(ip->i_ffs1_rdev), minor(ip->i_ffs1_rdev)); 519 else 520 (void)printf(" %7s", name); 521 else 522 (void)printf(" %7qd", ip->i_ffs1_size); 523 return (0); 524} 525 526void 527ext2fs_header(void) 528{ 529 (void)printf(" FILEID IFLAG SZ"); 530} 531 532int 533ext2fs_print(struct vnode *vp) 534{ 535 int flag; 536 struct inode inode, *ip = &inode; 537 struct ext2fs_dinode di; 538 char flagbuf[16], *flags = flagbuf; 539 540 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 541 KGETRET(inode.i_e2din, &di, sizeof(struct ext2fs_dinode), 542 "vnode's dinode"); 543 544 inode.i_e2din = &di; 545 flag = ip->i_flag; 546 547#if 0 548 if (flag & IN_LOCKED) 549 *flags++ = 'L'; 550 if (flag & IN_WANTED) 551 *flags++ = 'W'; 552 if (flag & IN_LWAIT) 553 *flags++ = 'Z'; 554#endif 555 if (flag & IN_ACCESS) 556 *flags++ = 'A'; 557 if (flag & IN_CHANGE) 558 *flags++ = 'C'; 559 if (flag & IN_UPDATE) 560 *flags++ = 'U'; 561 if (flag & IN_MODIFIED) 562 *flags++ = 'M'; 563 if (flag & IN_RENAME) 564 *flags++ = 'R'; 565 if (flag & IN_SHLOCK) 566 *flags++ = 'S'; 567 if (flag & IN_EXLOCK) 568 *flags++ = 'E'; 569 if (flag == 0) 570 *flags++ = '-'; 571 *flags = '\0'; 572 573 (void)printf(" %6d %5s %2d", ip->i_number, flagbuf, ip->i_e2fs_size); 574 return (0); 575} 576 577void 578nfs_header(void) 579{ 580 (void)printf(" FILEID NFLAG RDEV|SZ"); 581} 582 583int 584nfs_print(struct vnode *vp) 585{ 586 struct nfsnode nfsnode, *np = &nfsnode; 587 char flagbuf[16], *flags = flagbuf; 588 int flag; 589 char *name; 590 mode_t type; 591 592 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); 593 flag = np->n_flag; 594 if (flag & NFLUSHWANT) 595 *flags++ = 'W'; 596 if (flag & NFLUSHINPROG) 597 *flags++ = 'P'; 598 if (flag & NMODIFIED) 599 *flags++ = 'M'; 600 if (flag & NWRITEERR) 601 *flags++ = 'E'; 602 if (flag & NACC) 603 *flags++ = 'A'; 604 if (flag & NUPD) 605 *flags++ = 'U'; 606 if (flag & NCHG) 607 *flags++ = 'C'; 608 if (flag == 0) 609 *flags++ = '-'; 610 *flags = '\0'; 611 612 (void)printf(" %6ld %5s", np->n_vattr.va_fileid, flagbuf); 613 type = np->n_vattr.va_mode & S_IFMT; 614 if (S_ISCHR(np->n_vattr.va_mode) || S_ISBLK(np->n_vattr.va_mode)) 615 if (usenumflag || 616 ((name = devname(np->n_vattr.va_rdev, type)) == NULL)) 617 (void)printf(" %2d,%-2d", major(np->n_vattr.va_rdev), 618 minor(np->n_vattr.va_rdev)); 619 else 620 (void)printf(" %7s", name); 621 else 622 (void)printf(" %7qd", np->n_size); 623 return (0); 624} 625 626/* 627 * Given a pointer to a mount structure in kernel space, 628 * read it in and return a usable pointer to it. 629 */ 630struct mount * 631getmnt(struct mount *maddr) 632{ 633 static struct mtab { 634 struct mtab *next; 635 struct mount *maddr; 636 struct mount mount; 637 } *mhead = NULL; 638 struct mtab *mt; 639 640 for (mt = mhead; mt != NULL; mt = mt->next) 641 if (maddr == mt->maddr) 642 return (&mt->mount); 643 if ((mt = malloc(sizeof(struct mtab))) == NULL) 644 err(1, "malloc: mount table"); 645 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); 646 mt->maddr = maddr; 647 mt->next = mhead; 648 mhead = mt; 649 return (&mt->mount); 650} 651 652void 653mount_print(struct mount *mp) 654{ 655 int flags; 656 657 (void)printf("*** MOUNT "); 658 (void)printf("%.*s %s on %s", MFSNAMELEN, 659 mp->mnt_stat.f_fstypename, mp->mnt_stat.f_mntfromname, 660 mp->mnt_stat.f_mntonname); 661 if ((flags = mp->mnt_flag)) { 662 char *comma = "("; 663 664 putchar(' '); 665 /* user visible flags */ 666 if (flags & MNT_RDONLY) { 667 (void)printf("%srdonly", comma); 668 flags &= ~MNT_RDONLY; 669 comma = ","; 670 } 671 if (flags & MNT_SYNCHRONOUS) { 672 (void)printf("%ssynchronous", comma); 673 flags &= ~MNT_SYNCHRONOUS; 674 comma = ","; 675 } 676 if (flags & MNT_NOEXEC) { 677 (void)printf("%snoexec", comma); 678 flags &= ~MNT_NOEXEC; 679 comma = ","; 680 } 681 if (flags & MNT_NOSUID) { 682 (void)printf("%snosuid", comma); 683 flags &= ~MNT_NOSUID; 684 comma = ","; 685 } 686 if (flags & MNT_NODEV) { 687 (void)printf("%snodev", comma); 688 flags &= ~MNT_NODEV; 689 comma = ","; 690 } 691 if (flags & MNT_ASYNC) { 692 (void)printf("%sasync", comma); 693 flags &= ~MNT_ASYNC; 694 comma = ","; 695 } 696 if (flags & MNT_EXRDONLY) { 697 (void)printf("%sexrdonly", comma); 698 flags &= ~MNT_EXRDONLY; 699 comma = ","; 700 } 701 if (flags & MNT_EXPORTED) { 702 (void)printf("%sexport", comma); 703 flags &= ~MNT_EXPORTED; 704 comma = ","; 705 } 706 if (flags & MNT_DEFEXPORTED) { 707 (void)printf("%sdefdexported", comma); 708 flags &= ~MNT_DEFEXPORTED; 709 comma = ","; 710 } 711 if (flags & MNT_EXPORTANON) { 712 (void)printf("%sexportanon", comma); 713 flags &= ~MNT_EXPORTANON; 714 comma = ","; 715 } 716 if (flags & MNT_EXKERB) { 717 (void)printf("%sexkerb", comma); 718 flags &= ~MNT_EXKERB; 719 comma = ","; 720 } 721 if (flags & MNT_LOCAL) { 722 (void)printf("%slocal", comma); 723 flags &= ~MNT_LOCAL; 724 comma = ","; 725 } 726 if (flags & MNT_QUOTA) { 727 (void)printf("%squota", comma); 728 flags &= ~MNT_QUOTA; 729 comma = ","; 730 } 731 if (flags & MNT_ROOTFS) { 732 (void)printf("%srootfs", comma); 733 flags &= ~MNT_ROOTFS; 734 comma = ","; 735 } 736 if (flags & MNT_NOATIME) { 737 (void)printf("%snoatime", comma); 738 flags &= ~MNT_NOATIME; 739 comma = ","; 740 } 741 /* filesystem control flags */ 742 if (flags & MNT_UPDATE) { 743 (void)printf("%supdate", comma); 744 flags &= ~MNT_UPDATE; 745 comma = ","; 746 } 747 if (flags & MNT_DELEXPORT) { 748 (void)printf("%sdelexport", comma); 749 flags &= ~MNT_DELEXPORT; 750 comma = ","; 751 } 752 if (flags & MNT_RELOAD) { 753 (void)printf("%sreload", comma); 754 flags &= ~MNT_RELOAD; 755 comma = ","; 756 } 757 if (flags & MNT_FORCE) { 758 (void)printf("%sforce", comma); 759 flags &= ~MNT_FORCE; 760 comma = ","; 761 } 762 if (flags & MNT_WANTRDWR) { 763 (void)printf("%swantrdwr", comma); 764 flags &= ~MNT_WANTRDWR; 765 comma = ","; 766 } 767 if (flags & MNT_SOFTDEP) { 768 (void)printf("%ssoftdep", comma); 769 flags &= ~MNT_SOFTDEP; 770 comma = ","; 771 } 772 if (flags) 773 (void)printf("%sunknown_flags:%x", comma, flags); 774 (void)printf(")"); 775 } 776 (void)printf("\n"); 777} 778 779struct e_vnode * 780loadvnodes(int *avnodes) 781{ 782 int mib[2]; 783 size_t copysize; 784 struct e_vnode *vnodebase; 785 786 if (memf != NULL) { 787 /* 788 * do it by hand 789 */ 790 return (kinfo_vnodes(avnodes)); 791 } 792 mib[0] = CTL_KERN; 793 mib[1] = KERN_VNODE; 794 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) 795 err(1, "sysctl: KERN_VNODE"); 796 if ((vnodebase = malloc(copysize)) == NULL) 797 err(1, "malloc: vnode table"); 798 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) 799 err(1, "sysctl: KERN_VNODE"); 800 if (copysize % sizeof(struct e_vnode)) 801 errx(1, "vnode size mismatch"); 802 *avnodes = copysize / sizeof(struct e_vnode); 803 804 return (vnodebase); 805} 806 807/* 808 * simulate what a running kernel does in kinfo_vnode 809 */ 810struct e_vnode * 811kinfo_vnodes(int *avnodes) 812{ 813 struct mntlist kvm_mountlist; 814 struct mount *mp, mount; 815 struct vnode *vp, vnode; 816 char *vbuf, *evbuf, *bp; 817 int mib[2], numvnodes; 818 size_t num; 819 820 if (kd == 0) { 821 mib[0] = CTL_KERN; 822 mib[1] = KERN_NUMVNODES; 823 num = sizeof(numvnodes); 824 if (sysctl(mib, 2, &numvnodes, &num, NULL, 0) < 0) 825 err(1, "sysctl(KERN_NUMVNODES) failed"); 826 } else 827 KGET(V_NUMV, numvnodes); 828 if ((vbuf = calloc(numvnodes + 20, 829 sizeof(struct vnode *) + sizeof(struct vnode))) == NULL) 830 err(1, "malloc: vnode buffer"); 831 bp = vbuf; 832 evbuf = vbuf + (numvnodes + 20) * 833 (sizeof(struct vnode *) + sizeof(struct vnode)); 834 KGET(V_MOUNTLIST, kvm_mountlist); 835 for (num = 0, mp = CIRCLEQ_FIRST(&kvm_mountlist); ; 836 mp = CIRCLEQ_NEXT(&mount, mnt_list)) { 837 KGET2(mp, &mount, sizeof(mount), "mount entry"); 838 for (vp = LIST_FIRST(&mount.mnt_vnodelist); 839 vp != NULL; vp = LIST_NEXT(&vnode, v_mntvnodes)) { 840 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 841 if ((bp + sizeof(struct vnode *) + 842 sizeof(struct vnode)) > evbuf) 843 /* XXX - should realloc */ 844 errx(1, "no more room for vnodes"); 845 memmove(bp, &vp, sizeof(struct vnode *)); 846 bp += sizeof(struct vnode *); 847 memmove(bp, &vnode, sizeof(struct vnode)); 848 bp += sizeof(struct vnode); 849 num++; 850 } 851 if (mp == CIRCLEQ_LAST(&kvm_mountlist)) 852 break; 853 } 854 *avnodes = num; 855 return ((struct e_vnode *)vbuf); 856} 857 858const char hdr[] = 859" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n"; 860 861void 862tty2itty(struct tty *tp, struct itty *itp) 863{ 864 itp->t_dev = tp->t_dev; 865 itp->t_rawq_c_cc = tp->t_rawq.c_cc; 866 itp->t_canq_c_cc = tp->t_canq.c_cc; 867 itp->t_outq_c_cc = tp->t_outq.c_cc; 868 itp->t_hiwat = tp->t_hiwat; 869 itp->t_lowat = tp->t_lowat; 870 itp->t_column = tp->t_column; 871 itp->t_state = tp->t_state; 872 itp->t_session = tp->t_session; 873 if (tp->t_pgrp != NULL) 874 KGET2(&tp->t_pgrp->pg_id, &itp->t_pgrp_pg_id, sizeof(pid_t), "pgid"); 875 itp->t_line = tp->t_line; 876} 877 878void 879ttymode(void) 880{ 881 struct ttylist_head tty_head; 882 struct tty *tp, tty; 883 int mib[3], ntty, i; 884 struct itty itty, *itp; 885 size_t nlen; 886 887 if (kd == 0) { 888 mib[0] = CTL_KERN; 889 mib[1] = KERN_TTYCOUNT; 890 nlen = sizeof(ntty); 891 if (sysctl(mib, 2, &ntty, &nlen, NULL, 0) < 0) 892 err(1, "sysctl(KERN_TTYCOUNT) failed"); 893 } else 894 KGET(TTY_NTTY, ntty); 895 (void)printf("%d terminal device%s\n", ntty, ntty == 1 ? "" : "s"); 896 (void)printf("%s", hdr); 897 if (kd == 0) { 898 mib[0] = CTL_KERN; 899 mib[1] = KERN_TTY; 900 mib[2] = KERN_TTY_INFO; 901 nlen = ntty * sizeof(struct itty); 902 if ((itp = malloc(nlen)) == NULL) 903 err(1, "malloc"); 904 if (sysctl(mib, 3, itp, &nlen, NULL, 0) < 0) 905 err(1, "sysctl(KERN_TTY_INFO) failed"); 906 for (i = 0; i < ntty; i++) 907 ttyprt(&itp[i]); 908 free(itp); 909 } else { 910 KGET(TTY_TTYLIST, tty_head); 911 for (tp = TAILQ_FIRST(&tty_head); tp; 912 tp = TAILQ_NEXT(&tty, tty_link)) { 913 KGET2(tp, &tty, sizeof tty, "tty struct"); 914 tty2itty(&tty, &itty); 915 ttyprt(&itty); 916 } 917 } 918} 919 920struct { 921 int flag; 922 char val; 923} ttystates[] = { 924 { TS_WOPEN, 'W'}, 925 { TS_ISOPEN, 'O'}, 926 { TS_CARR_ON, 'C'}, 927 { TS_TIMEOUT, 'T'}, 928 { TS_FLUSH, 'F'}, 929 { TS_BUSY, 'B'}, 930 { TS_ASLEEP, 'A'}, 931 { TS_XCLUDE, 'X'}, 932 { TS_TTSTOP, 'S'}, 933 { TS_TBLOCK, 'K'}, 934 { TS_ASYNC, 'Y'}, 935 { TS_BKSL, 'D'}, 936 { TS_ERASE, 'E'}, 937 { TS_LNCH, 'L'}, 938 { TS_TYPEN, 'P'}, 939 { TS_CNTTB, 'N'}, 940 { 0, '\0'}, 941}; 942 943void 944ttyprt(struct itty *tp) 945{ 946 char *name, state[20]; 947 int i, j; 948 949 if (usenumflag || (name = devname(tp->t_dev, S_IFCHR)) == NULL) 950 (void)printf("%2d,%-3d ", major(tp->t_dev), minor(tp->t_dev)); 951 else 952 (void)printf("%7s ", name); 953 (void)printf("%3d %4d ", tp->t_rawq_c_cc, tp->t_canq_c_cc); 954 (void)printf("%4d %4d %3d %6d ", tp->t_outq_c_cc, 955 tp->t_hiwat, tp->t_lowat, tp->t_column); 956 for (i = j = 0; ttystates[i].flag; i++) 957 if (tp->t_state&ttystates[i].flag) 958 state[j++] = ttystates[i].val; 959 if (j == 0) 960 state[j++] = '-'; 961 state[j] = '\0'; 962 (void)printf("%-6s %8lx", state, (u_long)tp->t_session & ~KERNBASE); 963 (void)printf("%6d ", tp->t_pgrp_pg_id); 964 switch (tp->t_line) { 965 case TTYDISC: 966 (void)printf("term\n"); 967 break; 968 case TABLDISC: 969 (void)printf("tab\n"); 970 break; 971 case SLIPDISC: 972 (void)printf("slip\n"); 973 break; 974 case PPPDISC: 975 (void)printf("ppp\n"); 976 break; 977 case STRIPDISC: 978 (void)printf("strip\n"); 979 break; 980 case NMEADISC: 981 (void)printf("nmea\n"); 982 break; 983 default: 984 (void)printf("%d\n", tp->t_line); 985 break; 986 } 987} 988 989void 990filemode(void) 991{ 992 struct file fp, *ffp, *addr; 993 char *buf, flagbuf[16], *fbp; 994 static char *dtypes[] = { "???", "inode", "socket" }; 995 int mib[2], maxfile, nfile; 996 size_t len; 997 998 globalnl = vnodenl; 999 1000 if (kd == 0) { 1001 mib[0] = CTL_KERN; 1002 mib[1] = KERN_MAXFILES; 1003 len = sizeof(maxfile); 1004 if (sysctl(mib, 2, &maxfile, &len, NULL, 0) < 0) 1005 err(1, "sysctl(KERN_MAXFILES) failed"); 1006 if (totalflag) { 1007 mib[0] = CTL_KERN; 1008 mib[1] = KERN_NFILES; 1009 len = sizeof(nfile); 1010 if (sysctl(mib, 2, &nfile, &len, NULL, 0) < 0) 1011 err(1, "sysctl(KERN_NFILES) failed"); 1012 } 1013 } else { 1014 KGET(FNL_MAXFILE, maxfile); 1015 if (totalflag) { 1016 KGET(FNL_NFILE, nfile); 1017 (void)printf("%3d/%3d files\n", nfile, maxfile); 1018 return; 1019 } 1020 } 1021 1022 if (getfiles(&buf, &len) == -1) 1023 return; 1024 /* 1025 * Getfiles returns in malloc'd memory a pointer to the first file 1026 * structure, and then an array of file structs (whose addresses are 1027 * derivable from the previous entry). 1028 */ 1029 addr = LIST_FIRST((struct filelist *)buf); 1030 ffp = (struct file *)(buf + sizeof(struct filelist)); 1031 nfile = (len - sizeof(struct filelist)) / sizeof(struct file); 1032 1033 (void)printf("%d/%d open files\n", nfile, maxfile); 1034 1035 (void)printf("%*s TYPE FLG CNT MSG %*s OFFSET\n", 1036 2 * (int)sizeof(long), "LOC", 2 * (int)sizeof(long), "DATA"); 1037 for (; (char *)ffp < buf + len; addr = LIST_NEXT(ffp, f_list), ffp++) { 1038 memmove(&fp, ffp, sizeof fp); 1039 if ((unsigned)fp.f_type > DTYPE_SOCKET) 1040 continue; 1041 (void)printf("%0*lx ", 2 * (int)sizeof(long), (long)addr); 1042 (void)printf("%-8.8s", dtypes[fp.f_type]); 1043 fbp = flagbuf; 1044 if (fp.f_flag & FREAD) 1045 *fbp++ = 'R'; 1046 if (fp.f_flag & FWRITE) 1047 *fbp++ = 'W'; 1048 if (fp.f_flag & FAPPEND) 1049 *fbp++ = 'A'; 1050 if (fp.f_flag & FHASLOCK) 1051 *fbp++ = 'L'; 1052 if (fp.f_flag & FASYNC) 1053 *fbp++ = 'I'; 1054 *fbp = '\0'; 1055 (void)printf("%6s %3ld", flagbuf, fp.f_count); 1056 (void)printf(" %3ld", fp.f_msgcount); 1057 (void)printf(" %0*lx", 2 * (int)sizeof(long), (long)fp.f_data); 1058 1059 if (fp.f_offset == (off_t)-1) 1060 (void)printf(" *\n"); 1061 else if (fp.f_offset < 0) 1062 (void)printf(" %llx\n", (long long)fp.f_offset); 1063 else 1064 (void)printf(" %lld\n", (long long)fp.f_offset); 1065 } 1066 free(buf); 1067} 1068 1069int 1070getfiles(char **abuf, size_t *alen) 1071{ 1072 size_t len; 1073 int mib[2]; 1074 char *buf; 1075 1076 /* 1077 * XXX 1078 * Add emulation of KINFO_FILE here. 1079 */ 1080 if (memf != NULL) 1081 errx(1, "files on dead kernel, not implemented"); 1082 1083 mib[0] = CTL_KERN; 1084 mib[1] = KERN_FILE; 1085 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 1086 warn("sysctl: KERN_FILE"); 1087 return (-1); 1088 } 1089 if ((buf = malloc(len)) == NULL) 1090 err(1, "malloc: KERN_FILE"); 1091 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 1092 warn("sysctl: KERN_FILE"); 1093 free(buf); 1094 return (-1); 1095 } 1096 *abuf = buf; 1097 *alen = len; 1098 return (0); 1099} 1100 1101/* 1102 * swapmode is based on a program called swapinfo written 1103 * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 1104 */ 1105void 1106swapmode(void) 1107{ 1108 char *header; 1109 int hlen = 10, nswap; 1110 int bdiv, i, avail, nfree, npfree, used; 1111 long blocksize; 1112 struct swapent *swdev; 1113 1114 if (kflag) { 1115 header = "1K-blocks"; 1116 blocksize = 1024; 1117 hlen = strlen(header); 1118 } else 1119 header = getbsize(&hlen, &blocksize); 1120 1121 nswap = swapctl(SWAP_NSWAP, 0, 0); 1122 if (nswap == 0) { 1123 if (!totalflag) 1124 (void)printf("%-11s %*s %8s %8s %8s %s\n", 1125 "Device", hlen, header, 1126 "Used", "Avail", "Capacity", "Priority"); 1127 (void)printf("%-11s %*d %8d %8d %5.0f%%\n", 1128 "Total", hlen, 0, 0, 0, 0.0); 1129 return; 1130 } 1131 if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) 1132 err(1, "malloc"); 1133 if (swapctl(SWAP_STATS, swdev, nswap) == -1) 1134 err(1, "swapctl"); 1135 1136 if (!totalflag) 1137 (void)printf("%-11s %*s %8s %8s %8s %s\n", 1138 "Device", hlen, header, 1139 "Used", "Avail", "Capacity", "Priority"); 1140 1141 /* Run through swap list, doing the funky monkey. */ 1142 bdiv = blocksize / DEV_BSIZE; 1143 avail = nfree = npfree = 0; 1144 for (i = 0; i < nswap; i++) { 1145 int xsize, xfree; 1146 1147 if (!(swdev[i].se_flags & SWF_ENABLE)) 1148 continue; 1149 1150 if (!totalflag) { 1151 if (usenumflag) 1152 (void)printf("%2d,%-2d %*d ", 1153 major(swdev[i].se_dev), 1154 minor(swdev[i].se_dev), 1155 hlen, swdev[i].se_nblks / bdiv); 1156 else 1157 (void)printf("%-11s %*d ", swdev[i].se_path, 1158 hlen, swdev[i].se_nblks / bdiv); 1159 } 1160 1161 xsize = swdev[i].se_nblks; 1162 used = swdev[i].se_inuse; 1163 xfree = xsize - used; 1164 nfree += (xsize - used); 1165 npfree++; 1166 avail += xsize; 1167 if (totalflag) 1168 continue; 1169 (void)printf("%8d %8d %5.0f%% %d\n", 1170 used / bdiv, xfree / bdiv, 1171 (double)used / (double)xsize * 100.0, 1172 swdev[i].se_priority); 1173 } 1174 free(swdev); 1175 1176 /* 1177 * If only one partition has been set up via swapon(8), we don't 1178 * need to bother with totals. 1179 */ 1180 used = avail - nfree; 1181 if (totalflag) { 1182 (void)printf("%dM/%dM swap space\n", 1183 used / (1048576 / DEV_BSIZE), 1184 avail / (1048576 / DEV_BSIZE)); 1185 return; 1186 } 1187 if (npfree > 1) { 1188 (void)printf("%-11s %*d %8d %8d %5.0f%%\n", 1189 "Total", hlen, avail / bdiv, used / bdiv, nfree / bdiv, 1190 (double)used / (double)avail * 100.0); 1191 } 1192} 1193 1194void 1195usage(void) 1196{ 1197 (void)fprintf(stderr, "usage: " 1198 "pstat [-fknsTtv] [-d format] [-M core] [-N system] [symbols]\n"); 1199 exit(1); 1200} 1201