| 1 | /*- |
| 2 | * Copyright (c) 1980, 1991, 1993, 1994 |
| 3 | * The Regents of the University of California. All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * 1. Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer in the |
| 12 | * documentation and/or other materials provided with the distribution. |
| 13 | * 3. Neither the name of the University nor the names of its contributors |
| 14 | * may be used to endorse or promote products derived from this software |
| 15 | * without specific prior written permission. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 | * SUCH DAMAGE. |
| 28 | * |
| 29 | * @(#) Copyright (c) 1980, 1991, 1993, 1994 The Regents of the University of California. All rights reserved. |
| 30 | * @(#)pstat.c 8.16 (Berkeley) 5/9/95 |
| 31 | * $FreeBSD: src/usr.sbin/pstat/pstat.c,v 1.49.2.5 2002/07/12 09:12:49 des Exp $ |
| 32 | */ |
| 33 | |
| 34 | #include <sys/user.h> |
| 35 | #include <sys/kinfo.h> |
| 36 | #include <sys/param.h> |
| 37 | #include <sys/time.h> |
| 38 | #include <sys/vnode.h> |
| 39 | #include <sys/ucred.h> |
| 40 | #include <sys/file.h> |
| 41 | #include <vfs/ufs/quota.h> |
| 42 | #include <vfs/ufs/inode.h> |
| 43 | #include <sys/mount.h> |
| 44 | #include <sys/uio.h> |
| 45 | #include <sys/namei.h> |
| 46 | #include <vfs/union/union.h> |
| 47 | #include <sys/stat.h> |
| 48 | #include <nfs/rpcv2.h> |
| 49 | #include <nfs/nfsproto.h> |
| 50 | #include <nfs/nfs.h> |
| 51 | #include <nfs/nfsnode.h> |
| 52 | #include <sys/ioctl.h> |
| 53 | #include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */ |
| 54 | #include <sys/tty.h> |
| 55 | #include <sys/conf.h> |
| 56 | #include <sys/blist.h> |
| 57 | |
| 58 | #include <sys/sysctl.h> |
| 59 | |
| 60 | #include <err.h> |
| 61 | #include <fcntl.h> |
| 62 | #include <kvm.h> |
| 63 | #include <limits.h> |
| 64 | #include <nlist.h> |
| 65 | #include <stdio.h> |
| 66 | #include <stdlib.h> |
| 67 | #include <string.h> |
| 68 | #include <unistd.h> |
| 69 | |
| 70 | #ifdef USE_KCORE |
| 71 | # define KCORE_KINFO_WRAPPER |
| 72 | # include <kcore.h> |
| 73 | #else |
| 74 | # include <kinfo.h> |
| 75 | #endif |
| 76 | |
| 77 | enum { |
| 78 | NL_MOUNTLIST, |
| 79 | NL_NUMVNODES, |
| 80 | NL_RC_TTY, |
| 81 | NL_NRC_TTY, |
| 82 | NL_CY_TTY, |
| 83 | NL_NCY_TTY, |
| 84 | NL_SI_TTY, |
| 85 | NL_SI_NPORTS, |
| 86 | }; |
| 87 | |
| 88 | const size_t NL_LAST_MANDATORY = NL_NUMVNODES; |
| 89 | |
| 90 | struct nlist nl[] = { |
| 91 | { "_mountlist", 0, 0, 0, 0 }, /* address of head of mount list. */ |
| 92 | { "_numvnodes", 0, 0, 0, 0 }, |
| 93 | { "_rc_tty", 0, 0, 0, 0 }, |
| 94 | { "_nrc_tty", 0, 0, 0, 0 }, |
| 95 | { "_cy_tty", 0, 0, 0, 0 }, |
| 96 | { "_ncy_tty", 0, 0, 0, 0 }, |
| 97 | { "_si__tty", 0, 0, 0, 0 }, |
| 98 | { "_si_Nports", 0, 0, 0, 0 }, |
| 99 | { "", 0, 0, 0, 0 } |
| 100 | }; |
| 101 | |
| 102 | int usenumflag; |
| 103 | int totalflag; |
| 104 | int swapflag; |
| 105 | char *nlistf = NULL; |
| 106 | char *memf = NULL; |
| 107 | kvm_t *kd; |
| 108 | |
| 109 | const char *usagestr; |
| 110 | |
| 111 | struct { |
| 112 | int m_flag; |
| 113 | const char *m_name; |
| 114 | } mnt_flags[] = { |
| 115 | { MNT_RDONLY, "rdonly" }, |
| 116 | { MNT_SYNCHRONOUS, "sync" }, |
| 117 | { MNT_NOEXEC, "noexec" }, |
| 118 | { MNT_NOSUID, "nosuid" }, |
| 119 | { MNT_NODEV, "nodev" }, |
| 120 | { MNT_UNION, "union" }, |
| 121 | { MNT_ASYNC, "async" }, |
| 122 | { MNT_SUIDDIR, "suiddir" }, |
| 123 | { MNT_SOFTDEP, "softdep" }, |
| 124 | { MNT_NOSYMFOLLOW, "nosymfollow" }, |
| 125 | { MNT_NOATIME, "noatime" }, |
| 126 | { MNT_NOCLUSTERR, "noclusterread" }, |
| 127 | { MNT_NOCLUSTERW, "noclusterwrite" }, |
| 128 | { MNT_EXRDONLY, "exrdonly" }, |
| 129 | { MNT_EXPORTED, "exported" }, |
| 130 | { MNT_DEFEXPORTED, "defexported" }, |
| 131 | { MNT_EXPORTANON, "exportanon" }, |
| 132 | { MNT_EXKERB, "exkerb" }, |
| 133 | { MNT_EXPUBLIC, "public" }, |
| 134 | { MNT_LOCAL, "local" }, |
| 135 | { MNT_QUOTA, "quota" }, |
| 136 | { MNT_ROOTFS, "rootfs" }, |
| 137 | { MNT_USER, "user" }, |
| 138 | { MNT_IGNORE, "ignore" }, |
| 139 | { MNT_UPDATE, "update" }, |
| 140 | { MNT_DELEXPORT, "delexport" }, |
| 141 | { MNT_RELOAD, "reload" }, |
| 142 | { MNT_FORCE, "force" }, |
| 143 | { 0, NULL } |
| 144 | }; |
| 145 | |
| 146 | |
| 147 | #define SVAR(var) __STRING(var) /* to force expansion */ |
| 148 | #define KGET(idx, var) \ |
| 149 | KGET1(idx, &var, sizeof(var), SVAR(var)) |
| 150 | #define KGET1(idx, p, s, msg) \ |
| 151 | KGET2(nl[idx].n_value, p, s, msg) |
| 152 | #define KGET2(addr, p, s, msg) \ |
| 153 | if (kvm_read(kd, (u_long)(addr), p, s) != s) \ |
| 154 | warnx("cannot read %s: %s", msg, kvm_geterr(kd)) |
| 155 | #define KGETN(idx, var) \ |
| 156 | KGET1N(idx, &var, sizeof(var), SVAR(var)) |
| 157 | #define KGET1N(idx, p, s, msg) \ |
| 158 | KGET2N(nl[idx].n_value, p, s, msg) |
| 159 | #define KGET2N(addr, p, s, msg) \ |
| 160 | ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) |
| 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(void); |
| 168 | int getfiles(char **, int *); |
| 169 | struct mount * |
| 170 | getmnt(struct mount *); |
| 171 | struct e_vnode * |
| 172 | kinfo_vnodes(int *); |
| 173 | struct e_vnode * |
| 174 | loadvnodes(int *); |
| 175 | void mount_print(struct mount *); |
| 176 | void nfs_header(void); |
| 177 | int nfs_print(struct vnode *); |
| 178 | void swapmode(void); |
| 179 | void ttymode(void); |
| 180 | void ttyprt(struct tty *, int); |
| 181 | void ttytype(struct tty *, const char *, int, int, int); |
| 182 | void ufs_header(void); |
| 183 | int ufs_print(struct vnode *); |
| 184 | void union_header(void); |
| 185 | int union_print(struct vnode *); |
| 186 | static void usage(void); |
| 187 | void vnode_header(void); |
| 188 | void vnode_print(struct vnode *, struct vnode *); |
| 189 | void vnodemode(void); |
| 190 | |
| 191 | int |
| 192 | main(int argc, char **argv) |
| 193 | { |
| 194 | int ch, ret; |
| 195 | int fileflag, ttyflag, vnodeflag; |
| 196 | char buf[_POSIX2_LINE_MAX]; |
| 197 | const char *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 = "ghkmM:N:"; |
| 210 | usagestr = "swapinfo [-gkm] [-M core] [-N system]"; |
| 211 | } else { |
| 212 | opts = "TM:N:fhiknstv"; |
| 213 | usagestr = "pstat [-Tfknst] [-M core] [-N system]"; |
| 214 | } |
| 215 | |
| 216 | while ((ch = getopt(argc, argv, opts)) != -1) |
| 217 | switch (ch) { |
| 218 | case 'f': |
| 219 | fileflag = 1; |
| 220 | break; |
| 221 | case 'g': |
| 222 | if (setenv("BLOCKSIZE", "1G", 1) == -1) |
| 223 | warn("setenv: cannot set BLOCKSIZE=1K"); |
| 224 | break; |
| 225 | case 'k': |
| 226 | if (setenv("BLOCKSIZE", "1K", 1) == -1) |
| 227 | warn("setenv: cannot set BLOCKSIZE=1K"); |
| 228 | break; |
| 229 | case 'm': |
| 230 | if (setenv("BLOCKSIZE", "1M", 1) == -1) |
| 231 | warn("setenv: cannot set BLOCKSIZE=1K"); |
| 232 | break; |
| 233 | case 'M': |
| 234 | memf = optarg; |
| 235 | break; |
| 236 | case 'N': |
| 237 | nlistf = optarg; |
| 238 | break; |
| 239 | case 'n': |
| 240 | usenumflag = 1; |
| 241 | break; |
| 242 | case 's': |
| 243 | ++swapflag; |
| 244 | break; |
| 245 | case 'T': |
| 246 | totalflag = 1; |
| 247 | break; |
| 248 | case 't': |
| 249 | ttyflag = 1; |
| 250 | break; |
| 251 | case 'v': |
| 252 | case 'i': /* Backward compatibility. */ |
| 253 | errx(1, "vnode mode not supported"); |
| 254 | #if 0 |
| 255 | vnodeflag = 1; |
| 256 | break; |
| 257 | #endif |
| 258 | default: |
| 259 | usage(); |
| 260 | } |
| 261 | argc -= optind; |
| 262 | argv += optind; |
| 263 | |
| 264 | /* |
| 265 | * Discard setgid privileges if not the running kernel so that bad |
| 266 | * guys can't print interesting stuff from kernel memory. |
| 267 | */ |
| 268 | if (nlistf != NULL || memf != NULL) |
| 269 | setgid(getgid()); |
| 270 | |
| 271 | if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) |
| 272 | errx(1, "kvm_openfiles: %s", buf); |
| 273 | #ifdef USE_KCORE |
| 274 | if (kcore_wrapper_open(nlistf, memf, buf)) |
| 275 | errx(1, "kcore_open: %s", buf); |
| 276 | #endif |
| 277 | if ((ret = kvm_nlist(kd, nl)) != 0) { |
| 278 | size_t i; |
| 279 | int quit = 0; |
| 280 | |
| 281 | if (ret == -1) |
| 282 | errx(1, "kvm_nlist: %s", kvm_geterr(kd)); |
| 283 | for (i = 0; i < NL_LAST_MANDATORY; i++) { |
| 284 | if (!nl[i].n_value) { |
| 285 | quit = 1; |
| 286 | warnx("undefined symbol: %s", nl[i].n_name); |
| 287 | } |
| 288 | } |
| 289 | if (quit) |
| 290 | exit(1); |
| 291 | } |
| 292 | if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) |
| 293 | usage(); |
| 294 | if (fileflag || totalflag) |
| 295 | filemode(); |
| 296 | if (vnodeflag) |
| 297 | vnodemode(); |
| 298 | if (ttyflag) |
| 299 | ttymode(); |
| 300 | if (swapflag || totalflag) |
| 301 | swapmode(); |
| 302 | exit (0); |
| 303 | } |
| 304 | |
| 305 | static void |
| 306 | usage(void) |
| 307 | { |
| 308 | fprintf(stderr, "usage: %s\n", usagestr); |
| 309 | exit (1); |
| 310 | } |
| 311 | |
| 312 | struct e_vnode { |
| 313 | struct vnode *avnode; |
| 314 | struct vnode vnode; |
| 315 | }; |
| 316 | |
| 317 | void |
| 318 | vnodemode(void) |
| 319 | { |
| 320 | struct e_vnode *e_vnodebase, *endvnode, *evp; |
| 321 | struct vnode *vp; |
| 322 | struct mount *maddr, *mp = NULL; |
| 323 | int numvnodes; |
| 324 | |
| 325 | e_vnodebase = loadvnodes(&numvnodes); |
| 326 | if (totalflag) { |
| 327 | printf("%7d vnodes\n", numvnodes); |
| 328 | return; |
| 329 | } |
| 330 | endvnode = e_vnodebase + numvnodes; |
| 331 | printf("%d active vnodes\n", numvnodes); |
| 332 | |
| 333 | |
| 334 | #define ST mp->mnt_stat |
| 335 | maddr = NULL; |
| 336 | for (evp = e_vnodebase; evp < endvnode; evp++) { |
| 337 | vp = &evp->vnode; |
| 338 | if (vp->v_mount != maddr) { |
| 339 | /* |
| 340 | * New filesystem |
| 341 | */ |
| 342 | if ((mp = getmnt(vp->v_mount)) == NULL) |
| 343 | continue; |
| 344 | maddr = vp->v_mount; |
| 345 | mount_print(mp); |
| 346 | vnode_header(); |
| 347 | if (!strcmp(ST.f_fstypename, "ufs") || |
| 348 | !strcmp(ST.f_fstypename, "mfs")) |
| 349 | ufs_header(); |
| 350 | else if (!strcmp(ST.f_fstypename, "nfs")) |
| 351 | nfs_header(); |
| 352 | else if (!strcmp(ST.f_fstypename, "union")) |
| 353 | union_header(); |
| 354 | printf("\n"); |
| 355 | } |
| 356 | vnode_print(evp->avnode, vp); |
| 357 | if (!strcmp(ST.f_fstypename, "ufs") || |
| 358 | !strcmp(ST.f_fstypename, "mfs")) |
| 359 | ufs_print(vp); |
| 360 | else if (!strcmp(ST.f_fstypename, "nfs")) |
| 361 | nfs_print(vp); |
| 362 | else if (!strcmp(ST.f_fstypename, "union")) |
| 363 | union_print(vp); |
| 364 | printf("\n"); |
| 365 | } |
| 366 | free(e_vnodebase); |
| 367 | } |
| 368 | |
| 369 | void |
| 370 | vnode_header(void) |
| 371 | { |
| 372 | printf("ADDR TYP VFLAG USE HOLD"); |
| 373 | } |
| 374 | |
| 375 | void |
| 376 | vnode_print(struct vnode *avnode, struct vnode *vp) |
| 377 | { |
| 378 | const char *type; |
| 379 | char flags[32]; |
| 380 | char *fp = flags; |
| 381 | int flag; |
| 382 | int refs; |
| 383 | |
| 384 | /* |
| 385 | * set type |
| 386 | */ |
| 387 | switch (vp->v_type) { |
| 388 | case VNON: |
| 389 | type = "non"; break; |
| 390 | case VREG: |
| 391 | type = "reg"; break; |
| 392 | case VDIR: |
| 393 | type = "dir"; break; |
| 394 | case VBLK: |
| 395 | type = "blk"; break; |
| 396 | case VCHR: |
| 397 | type = "chr"; break; |
| 398 | case VLNK: |
| 399 | type = "lnk"; break; |
| 400 | case VSOCK: |
| 401 | type = "soc"; break; |
| 402 | case VFIFO: |
| 403 | type = "fif"; break; |
| 404 | case VBAD: |
| 405 | type = "bad"; break; |
| 406 | default: |
| 407 | type = "unk"; break; |
| 408 | } |
| 409 | /* |
| 410 | * gather flags |
| 411 | */ |
| 412 | flag = vp->v_flag; |
| 413 | if (flag & VROOT) |
| 414 | *fp++ = 'R'; |
| 415 | if (flag & VTEXT) |
| 416 | *fp++ = 'T'; |
| 417 | if (flag & VSYSTEM) |
| 418 | *fp++ = 'S'; |
| 419 | if (flag & VISTTY) |
| 420 | *fp++ = 't'; |
| 421 | #ifdef VXLOCK |
| 422 | if (flag & VXLOCK) |
| 423 | *fp++ = 'L'; |
| 424 | if (flag & VXWANT) |
| 425 | *fp++ = 'W'; |
| 426 | #endif |
| 427 | if (flag & VOBJBUF) |
| 428 | *fp++ = 'V'; |
| 429 | if (flag & (VAGE0 | VAGE1)) |
| 430 | *fp++ = 'a'; |
| 431 | #ifdef VDOOMED |
| 432 | if (flag & VDOOMED) |
| 433 | *fp++ = 'D'; |
| 434 | #endif |
| 435 | if (flag & VONWORKLST) |
| 436 | *fp++ = 'O'; |
| 437 | #ifdef VRECLAIMED |
| 438 | if (flag & VINACTIVE) |
| 439 | *fp++ = 'I'; |
| 440 | if (flag & VRECLAIMED) |
| 441 | *fp++ = 'X'; |
| 442 | #endif |
| 443 | |
| 444 | if (flag == 0) |
| 445 | *fp++ = '-'; |
| 446 | *fp = '\0'; |
| 447 | |
| 448 | /* |
| 449 | * Convert SYSREF ref counts into something more |
| 450 | * human readable for display. |
| 451 | */ |
| 452 | refs = vp->v_refcnt; |
| 453 | printf("%8lx %s %5s %08x %4d", |
| 454 | (u_long)(void *)avnode, type, flags, refs, vp->v_auxrefs); |
| 455 | } |
| 456 | |
| 457 | void |
| 458 | ufs_header(void) |
| 459 | { |
| 460 | printf(" FILEID IFLAG RDEV|SZ"); |
| 461 | } |
| 462 | |
| 463 | int |
| 464 | ufs_print(struct vnode *vp) |
| 465 | { |
| 466 | int flag; |
| 467 | struct inode inode, *ip = &inode; |
| 468 | char flagbuf[16], *flags = flagbuf; |
| 469 | char *name; |
| 470 | mode_t type; |
| 471 | |
| 472 | KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); |
| 473 | flag = ip->i_flag; |
| 474 | if (flag & IN_ACCESS) |
| 475 | *flags++ = 'A'; |
| 476 | if (flag & IN_CHANGE) |
| 477 | *flags++ = 'C'; |
| 478 | if (flag & IN_UPDATE) |
| 479 | *flags++ = 'U'; |
| 480 | if (flag & IN_MODIFIED) |
| 481 | *flags++ = 'M'; |
| 482 | if (flag & IN_RENAME) |
| 483 | *flags++ = 'R'; |
| 484 | if (flag & IN_SHLOCK) |
| 485 | *flags++ = 'S'; |
| 486 | if (flag & IN_EXLOCK) |
| 487 | *flags++ = 'E'; |
| 488 | if (flag & IN_HASHED) |
| 489 | *flags++ = 'H'; |
| 490 | if (flag & IN_LAZYMOD) |
| 491 | *flags++ = 'L'; |
| 492 | if (flag == 0) |
| 493 | *flags++ = '-'; |
| 494 | *flags = '\0'; |
| 495 | |
| 496 | printf(" %6ju %5s", (uintmax_t)ip->i_number, flagbuf); |
| 497 | type = ip->i_mode & S_IFMT; |
| 498 | if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) |
| 499 | if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL)) |
| 500 | printf(" %2d,%-2d", |
| 501 | major(ip->i_rdev), minor(ip->i_rdev)); |
| 502 | else |
| 503 | printf(" %7s", name); |
| 504 | else |
| 505 | printf(" %7ju", (uintmax_t)ip->i_size); |
| 506 | return (0); |
| 507 | } |
| 508 | |
| 509 | void |
| 510 | nfs_header(void) |
| 511 | { |
| 512 | printf(" FILEID NFLAG RDEV|SZ"); |
| 513 | } |
| 514 | |
| 515 | int |
| 516 | nfs_print(struct vnode *vp) |
| 517 | { |
| 518 | struct nfsnode nfsnode, *np = &nfsnode; |
| 519 | char flagbuf[16], *flags = flagbuf; |
| 520 | int flag; |
| 521 | char *name; |
| 522 | mode_t type; |
| 523 | |
| 524 | KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); |
| 525 | flag = np->n_flag; |
| 526 | if (flag & NFLUSHWANT) |
| 527 | *flags++ = 'W'; |
| 528 | if (flag & NFLUSHINPROG) |
| 529 | *flags++ = 'P'; |
| 530 | if (flag & NLMODIFIED) |
| 531 | *flags++ = 'M'; |
| 532 | if (flag & NRMODIFIED) |
| 533 | *flags++ = 'R'; |
| 534 | if (flag & NWRITEERR) |
| 535 | *flags++ = 'E'; |
| 536 | if (flag & NQNFSEVICTED) |
| 537 | *flags++ = 'G'; |
| 538 | if (flag & NACC) |
| 539 | *flags++ = 'A'; |
| 540 | if (flag & NUPD) |
| 541 | *flags++ = 'U'; |
| 542 | if (flag & NCHG) |
| 543 | *flags++ = 'C'; |
| 544 | if (flag & NLOCKED) |
| 545 | *flags++ = 'L'; |
| 546 | if (flag & NWANTED) |
| 547 | *flags++ = 'w'; |
| 548 | if (flag == 0) |
| 549 | *flags++ = '-'; |
| 550 | *flags = '\0'; |
| 551 | |
| 552 | #define VT np->n_vattr |
| 553 | printf(" %6ju %5s", (uintmax_t)VT.va_fileid, flagbuf); |
| 554 | type = VT.va_mode & S_IFMT; |
| 555 | if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode)) |
| 556 | if (usenumflag || ((name = devname((VT.va_rmajor << 8) | VT.va_rminor, type)) == NULL)) |
| 557 | printf(" %2d,%-2d", |
| 558 | VT.va_rmajor, VT.va_rminor); |
| 559 | else |
| 560 | printf(" %7s", name); |
| 561 | else |
| 562 | printf(" %7ju", (uintmax_t)np->n_size); |
| 563 | return (0); |
| 564 | } |
| 565 | |
| 566 | void |
| 567 | union_header(void) |
| 568 | { |
| 569 | printf(" UPPER LOWER"); |
| 570 | } |
| 571 | |
| 572 | int |
| 573 | union_print(struct vnode *vp) |
| 574 | { |
| 575 | struct union_node unode, *up = &unode; |
| 576 | |
| 577 | KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode"); |
| 578 | |
| 579 | printf(" %8lx %8lx", (u_long)(void *)up->un_uppervp, |
| 580 | (u_long)(void *)up->un_lowervp); |
| 581 | return (0); |
| 582 | } |
| 583 | |
| 584 | /* |
| 585 | * Given a pointer to a mount structure in kernel space, |
| 586 | * read it in and return a usable pointer to it. |
| 587 | */ |
| 588 | struct mount * |
| 589 | getmnt(struct mount *maddr) |
| 590 | { |
| 591 | static struct mtab { |
| 592 | struct mtab *next; |
| 593 | struct mount *maddr; |
| 594 | struct mount mount; |
| 595 | } *mhead = NULL; |
| 596 | struct mtab *mt; |
| 597 | |
| 598 | for (mt = mhead; mt != NULL; mt = mt->next) |
| 599 | if (maddr == mt->maddr) |
| 600 | return (&mt->mount); |
| 601 | if ((mt = malloc(sizeof(struct mtab))) == NULL) |
| 602 | errx(1, "malloc"); |
| 603 | KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); |
| 604 | mt->maddr = maddr; |
| 605 | mt->next = mhead; |
| 606 | mhead = mt; |
| 607 | return (&mt->mount); |
| 608 | } |
| 609 | |
| 610 | void |
| 611 | mount_print(struct mount *mp) |
| 612 | { |
| 613 | int flags; |
| 614 | |
| 615 | #define ST mp->mnt_stat |
| 616 | printf("*** MOUNT %s %s on %s", ST.f_fstypename, |
| 617 | ST.f_mntfromname, ST.f_mntonname); |
| 618 | if ((flags = mp->mnt_flag)) { |
| 619 | int i; |
| 620 | const char *sep = " ("; |
| 621 | |
| 622 | for (i = 0; mnt_flags[i].m_flag; i++) { |
| 623 | if (flags & mnt_flags[i].m_flag) { |
| 624 | printf("%s%s", sep, mnt_flags[i].m_name); |
| 625 | flags &= ~mnt_flags[i].m_flag; |
| 626 | sep = ","; |
| 627 | } |
| 628 | } |
| 629 | if (flags) |
| 630 | printf("%sunknown_flags:%x", sep, flags); |
| 631 | printf(")"); |
| 632 | } |
| 633 | printf("\n"); |
| 634 | #undef ST |
| 635 | } |
| 636 | |
| 637 | struct e_vnode * |
| 638 | loadvnodes(int *avnodes) |
| 639 | { |
| 640 | int mib[2]; |
| 641 | size_t copysize; |
| 642 | struct e_vnode *vnodebase; |
| 643 | |
| 644 | if (memf != NULL) { |
| 645 | /* |
| 646 | * do it by hand |
| 647 | */ |
| 648 | return (kinfo_vnodes(avnodes)); |
| 649 | } |
| 650 | mib[0] = CTL_KERN; |
| 651 | mib[1] = KERN_VNODE; |
| 652 | if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) |
| 653 | err(1, "sysctl: KERN_VNODE"); |
| 654 | if ((vnodebase = malloc(copysize)) == NULL) |
| 655 | errx(1, "malloc"); |
| 656 | if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) |
| 657 | err(1, "sysctl: KERN_VNODE"); |
| 658 | if (copysize % sizeof(struct e_vnode)) |
| 659 | errx(1, "vnode size mismatch"); |
| 660 | *avnodes = copysize / sizeof(struct e_vnode); |
| 661 | |
| 662 | return (vnodebase); |
| 663 | } |
| 664 | |
| 665 | /* |
| 666 | * simulate what a running kernel does in in kinfo_vnode |
| 667 | */ |
| 668 | struct e_vnode * |
| 669 | kinfo_vnodes(int *avnodes) |
| 670 | { |
| 671 | struct mntlist mountlist; |
| 672 | struct mount *mp, mounth, *mp_next; |
| 673 | struct vnode *vp, vnode, *vp_next; |
| 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(NL_NUMVNODES, numvnodes); |
| 681 | if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL) |
| 682 | errx(1, "malloc"); |
| 683 | bp = vbuf; |
| 684 | evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ); |
| 685 | KGET(NL_MOUNTLIST, mountlist); |
| 686 | for (num = 0, mp = TAILQ_FIRST(&mountlist); ; mp = mp_next) { |
| 687 | KGET2(mp, &mounth, sizeof(mounth), "mount entry"); |
| 688 | mp_next = TAILQ_NEXT(&mounth, mnt_list); |
| 689 | for (vp = TAILQ_FIRST(&mounth.mnt_nvnodelist); |
| 690 | vp != NULL; vp = vp_next) { |
| 691 | KGET2(vp, &vnode, sizeof(vnode), "vnode"); |
| 692 | vp_next = TAILQ_NEXT(&vnode, v_nmntvnodes); |
| 693 | if ((bp + VPTRSZ + VNODESZ) > evbuf) |
| 694 | /* XXX - should realloc */ |
| 695 | errx(1, "no more room for vnodes"); |
| 696 | memmove(bp, &vp, VPTRSZ); |
| 697 | bp += VPTRSZ; |
| 698 | memmove(bp, &vnode, VNODESZ); |
| 699 | bp += VNODESZ; |
| 700 | num++; |
| 701 | } |
| 702 | if (mp == TAILQ_LAST(&mountlist, mntlist)) |
| 703 | break; |
| 704 | } |
| 705 | *avnodes = num; |
| 706 | return ((struct e_vnode *)vbuf); |
| 707 | } |
| 708 | |
| 709 | char hdr[] = |
| 710 | " LINE RAW CAN OUT IHIWT ILOWT OHWT LWT COL STATE SESS PGID DISC\n"; |
| 711 | int ttyspace = 128; |
| 712 | |
| 713 | void |
| 714 | ttymode(void) |
| 715 | { |
| 716 | struct tty *tty; |
| 717 | struct tty ttyb[1000]; |
| 718 | int error; |
| 719 | size_t len, i; |
| 720 | |
| 721 | printf(hdr); |
| 722 | len = sizeof(ttyb); |
| 723 | error = sysctlbyname("kern.ttys", &ttyb, &len, 0, 0); |
| 724 | if (!error) { |
| 725 | len /= sizeof(ttyb[0]); |
| 726 | for (i = 0; i < len; i++) { |
| 727 | ttyprt(&ttyb[i], 0); |
| 728 | } |
| 729 | } |
| 730 | if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL) |
| 731 | errx(1, "malloc"); |
| 732 | if (nl[NL_NRC_TTY].n_type != 0) |
| 733 | ttytype(tty, "rc", NL_RC_TTY, NL_NRC_TTY, 0); |
| 734 | if (nl[NL_NCY_TTY].n_type != 0) |
| 735 | ttytype(tty, "cy", NL_CY_TTY, NL_NCY_TTY, 0); |
| 736 | if (nl[NL_SI_NPORTS].n_type != 0) |
| 737 | ttytype(tty, "si", NL_SI_TTY, NL_SI_NPORTS, 1); |
| 738 | free(tty); |
| 739 | } |
| 740 | |
| 741 | void |
| 742 | ttytype(struct tty *tty, const char *name, int type, int number, int indir) |
| 743 | { |
| 744 | struct tty *tp; |
| 745 | int ntty; |
| 746 | struct tty **ttyaddr; |
| 747 | |
| 748 | if (tty == NULL) |
| 749 | return; |
| 750 | KGET(number, ntty); |
| 751 | printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines"); |
| 752 | if (ntty > ttyspace) { |
| 753 | ttyspace = ntty; |
| 754 | if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == NULL) |
| 755 | errx(1, "realloc"); |
| 756 | } |
| 757 | if (indir) { |
| 758 | KGET(type, ttyaddr); |
| 759 | KGET2(ttyaddr, tty, (ssize_t)(ntty * sizeof(struct tty)), |
| 760 | "tty structs"); |
| 761 | } else { |
| 762 | KGET1(type, tty, (ssize_t)(ntty * sizeof(struct tty)), |
| 763 | "tty structs"); |
| 764 | } |
| 765 | printf(hdr); |
| 766 | for (tp = tty; tp < &tty[ntty]; tp++) |
| 767 | ttyprt(tp, tp - tty); |
| 768 | } |
| 769 | |
| 770 | struct { |
| 771 | int flag; |
| 772 | char val; |
| 773 | } ttystates[] = { |
| 774 | #ifdef TS_WOPEN |
| 775 | { TS_WOPEN, 'W'}, |
| 776 | #endif |
| 777 | { TS_ISOPEN, 'O'}, |
| 778 | { TS_CARR_ON, 'C'}, |
| 779 | #ifdef TS_CONNECTED |
| 780 | { TS_CONNECTED, 'c'}, |
| 781 | #endif |
| 782 | { TS_TIMEOUT, 'T'}, |
| 783 | { TS_FLUSH, 'F'}, |
| 784 | { TS_BUSY, 'B'}, |
| 785 | #ifdef TS_ASLEEP |
| 786 | { TS_ASLEEP, 'A'}, |
| 787 | #endif |
| 788 | #ifdef TS_SO_OLOWAT |
| 789 | { TS_SO_OLOWAT, 'A'}, |
| 790 | #endif |
| 791 | #ifdef TS_SO_OCOMPLETE |
| 792 | { TS_SO_OCOMPLETE, 'a'}, |
| 793 | #endif |
| 794 | { TS_XCLUDE, 'X'}, |
| 795 | { TS_TTSTOP, 'S'}, |
| 796 | #ifdef TS_CAR_OFLOW |
| 797 | { TS_CAR_OFLOW, 'm'}, |
| 798 | #endif |
| 799 | #ifdef TS_CTS_OFLOW |
| 800 | { TS_CTS_OFLOW, 'o'}, |
| 801 | #endif |
| 802 | #ifdef TS_DSR_OFLOW |
| 803 | { TS_DSR_OFLOW, 'd'}, |
| 804 | #endif |
| 805 | { TS_TBLOCK, 'K'}, |
| 806 | { TS_ASYNC, 'Y'}, |
| 807 | { TS_BKSL, 'D'}, |
| 808 | { TS_ERASE, 'E'}, |
| 809 | { TS_LNCH, 'L'}, |
| 810 | { TS_TYPEN, 'P'}, |
| 811 | { TS_CNTTB, 'N'}, |
| 812 | #ifdef TS_CAN_BYPASS_L_RINT |
| 813 | { TS_CAN_BYPASS_L_RINT, 'l'}, |
| 814 | #endif |
| 815 | #ifdef TS_SNOOP |
| 816 | { TS_SNOOP, 's'}, |
| 817 | #endif |
| 818 | #ifdef TS_ZOMBIE |
| 819 | { TS_ZOMBIE, 'Z'}, |
| 820 | #endif |
| 821 | { 0, '\0'}, |
| 822 | }; |
| 823 | |
| 824 | void |
| 825 | ttyprt(struct tty *tp, int line) |
| 826 | { |
| 827 | int i, j; |
| 828 | pid_t pgid; |
| 829 | char *name, state[20]; |
| 830 | dev_t dev; |
| 831 | |
| 832 | dev = (uintptr_t)tp->t_dev & 0xffff; /* XXX t_dev is really dev_t */ |
| 833 | |
| 834 | if (usenumflag || dev == 0 || (name = devname(dev, S_IFCHR)) == NULL) |
| 835 | printf("%7d ", line); |
| 836 | else |
| 837 | printf("%7s ", name); |
| 838 | printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); |
| 839 | printf("%3d %5d %5d %4d %3d %7d ", tp->t_outq.c_cc, |
| 840 | tp->t_ihiwat, tp->t_ilowat, tp->t_ohiwat, tp->t_olowat, |
| 841 | tp->t_column); |
| 842 | for (i = j = 0; ttystates[i].flag; i++) |
| 843 | if (tp->t_state&ttystates[i].flag) |
| 844 | state[j++] = ttystates[i].val; |
| 845 | if (j == 0) |
| 846 | state[j++] = '-'; |
| 847 | state[j] = '\0'; |
| 848 | printf("%-6s %8lx", state, (u_long)(void *)tp->t_session); |
| 849 | pgid = 0; |
| 850 | if (tp->t_pgrp != NULL) |
| 851 | KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); |
| 852 | printf("%6d ", pgid); |
| 853 | switch (tp->t_line) { |
| 854 | case TTYDISC: |
| 855 | printf("term\n"); |
| 856 | break; |
| 857 | case NTTYDISC: |
| 858 | printf("ntty\n"); |
| 859 | break; |
| 860 | case SLIPDISC: |
| 861 | printf("slip\n"); |
| 862 | break; |
| 863 | case PPPDISC: |
| 864 | printf("ppp\n"); |
| 865 | break; |
| 866 | default: |
| 867 | printf("%d\n", tp->t_line); |
| 868 | break; |
| 869 | } |
| 870 | } |
| 871 | |
| 872 | void |
| 873 | filemode(void) |
| 874 | { |
| 875 | struct kinfo_file *fp, *ofp; |
| 876 | size_t len; |
| 877 | char flagbuf[16], *fbp; |
| 878 | int maxfile, nfile; |
| 879 | static const char *dtypes[] = { "???", "inode", "socket" }; |
| 880 | |
| 881 | if (kinfo_get_maxfiles(&maxfile)) |
| 882 | err(1, "kinfo_get_maxfiles"); |
| 883 | if (totalflag) { |
| 884 | if (kinfo_get_openfiles(&nfile)) |
| 885 | err(1, "kinfo_get_openfiles"); |
| 886 | printf("%3d/%3d files\n", nfile, maxfile); |
| 887 | return; |
| 888 | } |
| 889 | if (kinfo_get_files(&fp, &len)) |
| 890 | err(1, "kinfo_get_files"); |
| 891 | ofp = fp; |
| 892 | |
| 893 | printf("%zu/%d open files\n", len, maxfile); |
| 894 | printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); |
| 895 | for (; len-- > 0; fp++) { |
| 896 | if ((unsigned)fp->f_type > DTYPE_SOCKET) |
| 897 | continue; |
| 898 | printf("%p ", fp->f_file); |
| 899 | printf("%-8.8s", dtypes[fp->f_type]); |
| 900 | fbp = flagbuf; |
| 901 | if (fp->f_flag & FREAD) |
| 902 | *fbp++ = 'R'; |
| 903 | if (fp->f_flag & FWRITE) |
| 904 | *fbp++ = 'W'; |
| 905 | if (fp->f_flag & FAPPEND) |
| 906 | *fbp++ = 'A'; |
| 907 | #ifdef FSHLOCK /* currently gone */ |
| 908 | if (fp->f_flag & FSHLOCK) |
| 909 | *fbp++ = 'S'; |
| 910 | if (fp->f_flag & FEXLOCK) |
| 911 | *fbp++ = 'X'; |
| 912 | #endif |
| 913 | if (fp->f_flag & FASYNC) |
| 914 | *fbp++ = 'I'; |
| 915 | *fbp = '\0'; |
| 916 | printf("%6s %3d", flagbuf, fp->f_count); |
| 917 | printf(" %3d", fp->f_msgcount); |
| 918 | printf(" %8lx", (u_long)(void *)fp->f_data); |
| 919 | if (fp->f_offset < 0) |
| 920 | printf(" %jx\n", (uintmax_t)fp->f_offset); |
| 921 | else |
| 922 | printf(" %jd\n", (intmax_t)fp->f_offset); |
| 923 | } |
| 924 | free(ofp); |
| 925 | } |
| 926 | |
| 927 | /* |
| 928 | * swapmode is based on a program called swapinfo written |
| 929 | * by Kevin Lahey <kml@rokkaku.atl.ga.us>. |
| 930 | */ |
| 931 | void |
| 932 | swapmode(void) |
| 933 | { |
| 934 | struct kvm_swap kswap[16]; |
| 935 | int i; |
| 936 | int n; |
| 937 | int pagesize = getpagesize(); |
| 938 | const char *header; |
| 939 | int hlen; |
| 940 | long blocksize; |
| 941 | |
| 942 | n = kvm_getswapinfo( |
| 943 | kd, |
| 944 | kswap, |
| 945 | sizeof(kswap)/sizeof(kswap[0]), |
| 946 | ((swapflag > 1) ? SWIF_DUMP_TREE : 0) | SWIF_DEV_PREFIX |
| 947 | ); |
| 948 | |
| 949 | #define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize)) |
| 950 | |
| 951 | header = getbsize(&hlen, &blocksize); |
| 952 | if (totalflag == 0) { |
| 953 | printf("%-15s %*s %8s %8s %8s %s\n", |
| 954 | "Device", hlen, header, |
| 955 | "Used", "Avail", "Capacity", "Type"); |
| 956 | |
| 957 | for (i = 0; i < n; ++i) { |
| 958 | printf( |
| 959 | "%-15s %*d ", |
| 960 | kswap[i].ksw_devname, |
| 961 | hlen, |
| 962 | CONVERT(kswap[i].ksw_total) |
| 963 | ); |
| 964 | printf( |
| 965 | "%8d %8d %5.0f%% %s\n", |
| 966 | CONVERT(kswap[i].ksw_used), |
| 967 | CONVERT(kswap[i].ksw_total - kswap[i].ksw_used), |
| 968 | (double)kswap[i].ksw_used * 100.0 / |
| 969 | (double)kswap[i].ksw_total, |
| 970 | (kswap[i].ksw_flags & SW_SEQUENTIAL) ? |
| 971 | "Sequential" : "Interleaved" |
| 972 | ); |
| 973 | } |
| 974 | } |
| 975 | |
| 976 | if (totalflag) { |
| 977 | blocksize = 1024 * 1024; |
| 978 | |
| 979 | printf( |
| 980 | "%dM/%dM swap space\n", |
| 981 | CONVERT(kswap[n].ksw_used), |
| 982 | CONVERT(kswap[n].ksw_total) |
| 983 | ); |
| 984 | } else if (n > 1) { |
| 985 | printf( |
| 986 | "%-15s %*d %8d %8d %5.0f%%\n", |
| 987 | "Total", |
| 988 | hlen, |
| 989 | CONVERT(kswap[n].ksw_total), |
| 990 | CONVERT(kswap[n].ksw_used), |
| 991 | CONVERT(kswap[n].ksw_total - kswap[n].ksw_used), |
| 992 | (double)kswap[n].ksw_used * 100.0 / |
| 993 | (double)kswap[n].ksw_total |
| 994 | ); |
| 995 | } |
| 996 | } |