pstat.c revision 34185
1214501Srpaulo/*- 2214501Srpaulo * Copyright (c) 1980, 1991, 1993, 1994 3214501Srpaulo * The Regents of the University of California. All rights reserved. 4214501Srpaulo * 5252726Srpaulo * Redistribution and use in source and binary forms, with or without 6252726Srpaulo * modification, are permitted provided that the following conditions 7214501Srpaulo * are met: 8214501Srpaulo * 1. Redistributions of source code must retain the above copyright 9214501Srpaulo * notice, this list of conditions and the following disclaimer. 10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11214501Srpaulo * notice, this list of conditions and the following disclaimer in the 12214501Srpaulo * documentation and/or other materials provided with the distribution. 13214501Srpaulo * 3. All advertising materials mentioning features or use of this software 14214501Srpaulo * must display the following acknowledgement: 15214501Srpaulo * This product includes software developed by the University of 16214501Srpaulo * California, Berkeley and its contributors. 17214501Srpaulo * 4. Neither the name of the University nor the names of its contributors 18214501Srpaulo * may be used to endorse or promote products derived from this software 19214501Srpaulo * without specific prior written permission. 20214501Srpaulo * 21214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31214501Srpaulo * SUCH DAMAGE. 32214501Srpaulo */ 33214501Srpaulo 34214501Srpaulo#ifndef lint 35214501Srpaulostatic const char copyright[] = 36214501Srpaulo"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 37214501Srpaulo The Regents of the University of California. All rights reserved.\n"; 38214501Srpaulo#endif /* not lint */ 39214501Srpaulo 40214501Srpaulo#ifndef lint 41214501Srpaulo#if 0 42214501Srpaulostatic char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95"; 43214501Srpaulo#endif 44214501Srpaulostatic const char rcsid[] = 45214501Srpaulo "$Id: pstat.c,v 1.34 1998/01/06 05:33:28 dyson Exp $"; 46214501Srpaulo#endif /* not lint */ 47214501Srpaulo 48214501Srpaulo#include <sys/param.h> 49214501Srpaulo#include <sys/time.h> 50214501Srpaulo#include <sys/vnode.h> 51214501Srpaulo#include <sys/ucred.h> 52214501Srpaulo#define KERNEL 53214501Srpaulo#include <sys/file.h> 54214501Srpaulo#include <ufs/ufs/quota.h> 55214501Srpaulo#include <ufs/ufs/inode.h> 56214501Srpaulo#include <sys/mount.h> 57214501Srpaulo#include <sys/uio.h> 58214501Srpaulo#include <sys/namei.h> 59214501Srpaulo#include <miscfs/union/union.h> 60214501Srpaulo#undef KERNEL 61214501Srpaulo#include <sys/stat.h> 62214501Srpaulo#include <nfs/rpcv2.h> 63214501Srpaulo#include <nfs/nfsproto.h> 64214501Srpaulo#include <nfs/nfs.h> 65214501Srpaulo#include <nfs/nfsnode.h> 66214501Srpaulo#include <sys/ioctl.h> 67214501Srpaulo#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */ 68214501Srpaulo#include <sys/tty.h> 69214501Srpaulo#include <sys/conf.h> 70214501Srpaulo#include <sys/rlist.h> 71214501Srpaulo 72214501Srpaulo#include <sys/user.h> 73214501Srpaulo#include <sys/sysctl.h> 74214501Srpaulo 75214501Srpaulo#include <err.h> 76214501Srpaulo#include <fcntl.h> 77214501Srpaulo#include <kvm.h> 78214501Srpaulo#include <limits.h> 79214501Srpaulo#include <nlist.h> 80214501Srpaulo#include <stdio.h> 81214501Srpaulo#include <stdlib.h> 82214501Srpaulo#include <string.h> 83214501Srpaulo#include <unistd.h> 84214501Srpaulo 85214501Srpaulostruct nlist nl[] = { 86214501Srpaulo#define VM_SWAPLIST 0 87214501Srpaulo { "_swaplist" },/* list of free swap areas */ 88214501Srpaulo#define VM_SWDEVT 1 89214501Srpaulo { "_swdevt" }, /* list of swap devices and sizes */ 90214501Srpaulo#define VM_NSWAP 2 91214501Srpaulo { "_nswap" }, /* size of largest swap device */ 92214501Srpaulo#define VM_NSWDEV 3 93214501Srpaulo { "_nswdev" }, /* number of swap devices */ 94214501Srpaulo#define VM_DMMAX 4 95214501Srpaulo { "_dmmax" }, /* maximum size of a swap block */ 96214501Srpaulo#define V_MOUNTLIST 5 97214501Srpaulo { "_mountlist" }, /* address of head of mount list. */ 98214501Srpaulo#define V_NUMV 6 99214501Srpaulo { "_numvnodes" }, 100214501Srpaulo#define FNL_NFILE 7 101214501Srpaulo {"_nfiles"}, 102214501Srpaulo#define FNL_MAXFILE 8 103214501Srpaulo {"_maxfiles"}, 104214501Srpaulo#define NLMANDATORY FNL_MAXFILE /* names up to here are mandatory */ 105214501Srpaulo#define SCONS NLMANDATORY + 1 106214501Srpaulo { "_cons" }, 107214501Srpaulo#define SPTY NLMANDATORY + 2 108214501Srpaulo { "_pt_tty" }, 109214501Srpaulo#define SNPTY NLMANDATORY + 3 110214501Srpaulo { "_npty" }, 111214501Srpaulo 112214501Srpaulo#ifdef hp300 113214501Srpaulo#define SDCA (SNPTY+1) 114214501Srpaulo { "_dca_tty" }, 115214501Srpaulo#define SNDCA (SNPTY+2) 116214501Srpaulo { "_ndca" }, 117214501Srpaulo#define SDCM (SNPTY+3) 118214501Srpaulo { "_dcm_tty" }, 119214501Srpaulo#define SNDCM (SNPTY+4) 120214501Srpaulo { "_ndcm" }, 121214501Srpaulo#define SDCL (SNPTY+5) 122214501Srpaulo { "_dcl_tty" }, 123214501Srpaulo#define SNDCL (SNPTY+6) 124214501Srpaulo { "_ndcl" }, 125214501Srpaulo#define SITE (SNPTY+7) 126214501Srpaulo { "_ite_tty" }, 127214501Srpaulo#define SNITE (SNPTY+8) 128214501Srpaulo { "_nite" }, 129214501Srpaulo#endif 130214501Srpaulo 131214501Srpaulo#ifdef mips 132214501Srpaulo#define SDC (SNPTY+1) 133214501Srpaulo { "_dc_tty" }, 134214501Srpaulo#define SNDC (SNPTY+2) 135214501Srpaulo { "_dc_cnt" }, 136214501Srpaulo#endif 137214501Srpaulo 138214501Srpaulo#ifdef __FreeBSD__ 139214501Srpaulo#define SCCONS (SNPTY+1) 140214501Srpaulo { "_sccons" }, 141214501Srpaulo#define NSCCONS (SNPTY+2) 142214501Srpaulo { "_nsccons" }, 143214501Srpaulo#define SIO (SNPTY+3) 144214501Srpaulo { "_sio_tty" }, 145214501Srpaulo#define NSIO (SNPTY+4) 146214501Srpaulo { "_nsio_tty" }, 147214501Srpaulo#define RC (SNPTY+5) 148214501Srpaulo { "_rc_tty" }, 149214501Srpaulo#define NRC (SNPTY+6) 150214501Srpaulo { "_nrc_tty" }, 151214501Srpaulo#define CY (SNPTY+7) 152214501Srpaulo { "_cy_tty" }, 153214501Srpaulo#define NCY (SNPTY+8) 154214501Srpaulo { "_ncy_tty" }, 155214501Srpaulo#define SI (SNPTY+9) 156214501Srpaulo { "_si_tty" }, 157214501Srpaulo#define NSI (SNPTY+10) 158214501Srpaulo { "_si_Nports" }, 159214501Srpaulo#endif 160214501Srpaulo { "" } 161214501Srpaulo}; 162214501Srpaulo 163214501Srpauloint usenumflag; 164214501Srpauloint totalflag; 165214501Srpaulochar *nlistf = NULL; 166214501Srpaulochar *memf = NULL; 167214501Srpaulokvm_t *kd; 168214501Srpaulo 169214501Srpaulochar *usagestr; 170214501Srpaulo 171214501Srpaulostruct { 172214501Srpaulo int m_flag; 173214501Srpaulo const char *m_name; 174214501Srpaulo} mnt_flags[] = { 175214501Srpaulo { MNT_RDONLY, "rdonly" }, 176214501Srpaulo { MNT_SYNCHRONOUS, "sync" }, 177214501Srpaulo { MNT_NOEXEC, "noexec" }, 178214501Srpaulo { MNT_NOSUID, "nosuid" }, 179252726Srpaulo { MNT_NODEV, "nodev" }, 180252726Srpaulo { MNT_UNION, "union" }, 181214501Srpaulo { MNT_ASYNC, "async" }, 182214501Srpaulo { MNT_NOATIME, "noatime" }, 183214501Srpaulo { MNT_EXRDONLY, "exrdonly" }, 184214501Srpaulo { MNT_EXPORTED, "exported" }, 185246875Sdim { MNT_DEFEXPORTED, "defexported" }, 186214501Srpaulo { MNT_EXPORTANON, "exportanon" }, 187214501Srpaulo { MNT_EXKERB, "exkerb" }, 188214501Srpaulo { MNT_LOCAL, "local" }, 189214501Srpaulo { MNT_QUOTA, "quota" }, 190214501Srpaulo { MNT_ROOTFS, "rootfs" }, 191214501Srpaulo { MNT_USER, "user" }, 192214501Srpaulo { MNT_UPDATE, "update" }, 193214501Srpaulo { MNT_DELEXPORT }, 194214501Srpaulo { MNT_UPDATE, "update" }, 195214501Srpaulo { MNT_DELEXPORT, "delexport" }, 196214501Srpaulo { MNT_RELOAD, "reload" }, 197214501Srpaulo { MNT_FORCE, "force" }, 198214501Srpaulo#if 0 199214501Srpaulo { MNT_UNMOUNT, "unmount" }, 200214501Srpaulo { MNT_MWAIT, "mwait" }, 201214501Srpaulo { MNT_WANTRDWR, "wantrdwr" }, 202214501Srpaulo#endif 203214501Srpaulo { 0 } 204214501Srpaulo}; 205214501Srpaulo 206214501Srpaulo 207214501Srpaulo#define SVAR(var) __STRING(var) /* to force expansion */ 208214501Srpaulo#define KGET(idx, var) \ 209214501Srpaulo KGET1(idx, &var, sizeof(var), SVAR(var)) 210214501Srpaulo#define KGET1(idx, p, s, msg) \ 211214501Srpaulo KGET2(nl[idx].n_value, p, s, msg) 212214501Srpaulo#define KGET2(addr, p, s, msg) \ 213214501Srpaulo if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 214214501Srpaulo warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 215214501Srpaulo#define KGETRET(addr, p, s, msg) \ 216214501Srpaulo if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 217214501Srpaulo warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 218214501Srpaulo return (0); \ 219214501Srpaulo } 220214501Srpaulo 221214501Srpaulovoid filemode __P((void)); 222214501Srpauloint getfiles __P((char **, int *)); 223214501Srpaulostruct mount * 224214501Srpaulo getmnt __P((struct mount *)); 225214501Srpaulostruct e_vnode * 226214501Srpaulo kinfo_vnodes __P((int *)); 227214501Srpaulostruct e_vnode * 228214501Srpaulo loadvnodes __P((int *)); 229214501Srpaulovoid mount_print __P((struct mount *)); 230214501Srpaulovoid nfs_header __P((void)); 231214501Srpauloint nfs_print __P((struct vnode *)); 232214501Srpaulovoid swapmode __P((void)); 233214501Srpaulovoid ttymode __P((void)); 234214501Srpaulovoid ttyprt __P((struct tty *, int)); 235214501Srpaulovoid ttytype __P((struct tty *, char *, int, int, int)); 236214501Srpaulovoid ufs_header __P((void)); 237214501Srpauloint ufs_print __P((struct vnode *)); 238214501Srpaulovoid union_header __P((void)); 239214501Srpauloint union_print __P((struct vnode *)); 240214501Srpaulostatic void usage __P((void)); 241214501Srpaulovoid vnode_header __P((void)); 242214501Srpaulovoid vnode_print __P((struct vnode *, struct vnode *)); 243214501Srpaulovoid vnodemode __P((void)); 244214501Srpaulo 245214501Srpauloint 246214501Srpaulomain(argc, argv) 247214501Srpaulo int argc; 248214501Srpaulo char *argv[]; 249214501Srpaulo{ 250214501Srpaulo int ch, i, quit, ret; 251214501Srpaulo int fileflag, swapflag, ttyflag, vnodeflag; 252214501Srpaulo char buf[_POSIX2_LINE_MAX],*opts; 253214501Srpaulo 254214501Srpaulo fileflag = swapflag = ttyflag = vnodeflag = 0; 255214501Srpaulo 256214501Srpaulo /* We will behave like good old swapinfo if thus invoked */ 257214501Srpaulo opts = strrchr(argv[0],'/'); 258214501Srpaulo if (opts) 259214501Srpaulo opts++; 260214501Srpaulo else 261214501Srpaulo opts = argv[0]; 262214501Srpaulo if (!strcmp(opts,"swapinfo")) { 263214501Srpaulo swapflag = 1; 264214501Srpaulo opts = "kM:N:"; 265214501Srpaulo usagestr = "swapinfo [-k] [-M core] [-N system]"; 266214501Srpaulo } else { 267214501Srpaulo opts = "TM:N:fiknstv"; 268214501Srpaulo usagestr = "pstat [-Tfknstv] [-M core] [-N system]"; 269214501Srpaulo } 270214501Srpaulo 271214501Srpaulo while ((ch = getopt(argc, argv, opts)) != -1) 272214501Srpaulo switch (ch) { 273214501Srpaulo case 'f': 274214501Srpaulo fileflag = 1; 275214501Srpaulo break; 276214501Srpaulo case 'k': 277214501Srpaulo putenv("BLOCKSIZE=1K"); 278214501Srpaulo break; 279214501Srpaulo case 'M': 280214501Srpaulo memf = optarg; 281214501Srpaulo break; 282214501Srpaulo case 'N': 283214501Srpaulo nlistf = optarg; 284214501Srpaulo break; 285214501Srpaulo case 'n': 286214501Srpaulo usenumflag = 1; 287214501Srpaulo break; 288 case 's': 289 swapflag = 1; 290 break; 291 case 'T': 292 totalflag = 1; 293 break; 294 case 't': 295 ttyflag = 1; 296 break; 297 case 'v': 298 case 'i': /* Backward compatibility. */ 299 fprintf(stderr, "vnode mode not supported\n"); 300 exit(1); 301#if 0 302 vnodeflag = 1; 303 break; 304#endif 305 default: 306 usage(); 307 } 308 argc -= optind; 309 argv += optind; 310 311 /* 312 * Discard setgid privileges if not the running kernel so that bad 313 * guys can't print interesting stuff from kernel memory. 314 */ 315 if (nlistf != NULL || memf != NULL) 316 (void)setgid(getgid()); 317 318 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 319 errx(1, "kvm_openfiles: %s", buf); 320 if ((ret = kvm_nlist(kd, nl)) != 0) { 321 if (ret == -1) 322 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 323 for (i = quit = 0; i <= NLMANDATORY; i++) 324 if (!nl[i].n_value) { 325 quit = 1; 326 warnx("undefined symbol: %s", nl[i].n_name); 327 } 328 if (quit) 329 exit(1); 330 } 331 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) 332 usage(); 333 if (fileflag || totalflag) 334 filemode(); 335 if (vnodeflag) 336 vnodemode(); 337 if (ttyflag) 338 ttymode(); 339 if (swapflag || totalflag) 340 swapmode(); 341 exit (0); 342} 343 344static void 345usage() 346{ 347 fprintf(stderr, "usage: %s\n", usagestr); 348 exit (1); 349} 350 351struct e_vnode { 352 struct vnode *avnode; 353 struct vnode vnode; 354}; 355 356void 357vnodemode() 358{ 359 struct e_vnode *e_vnodebase, *endvnode, *evp; 360 struct vnode *vp; 361 struct mount *maddr, *mp; 362 int numvnodes; 363 364 e_vnodebase = loadvnodes(&numvnodes); 365 if (totalflag) { 366 (void)printf("%7d vnodes\n", numvnodes); 367 return; 368 } 369 endvnode = e_vnodebase + numvnodes; 370 (void)printf("%d active vnodes\n", numvnodes); 371 372 373#define ST mp->mnt_stat 374 maddr = NULL; 375 for (evp = e_vnodebase; evp < endvnode; evp++) { 376 vp = &evp->vnode; 377 if (vp->v_mount != maddr) { 378 /* 379 * New filesystem 380 */ 381 if ((mp = getmnt(vp->v_mount)) == NULL) 382 continue; 383 maddr = vp->v_mount; 384 mount_print(mp); 385 vnode_header(); 386 if (!strcmp(ST.f_fstypename, "ufs") || 387 !strcmp(ST.f_fstypename, "mfs")) 388 ufs_header(); 389 else if (!strcmp(ST.f_fstypename, "nfs")) 390 nfs_header(); 391 else if (!strcmp(ST.f_fstypename, "union")) 392 union_header(); 393 (void)printf("\n"); 394 } 395 vnode_print(evp->avnode, vp); 396 if (!strcmp(ST.f_fstypename, "ufs") || 397 !strcmp(ST.f_fstypename, "mfs")) 398 ufs_print(vp); 399 else if (!strcmp(ST.f_fstypename, "nfs")) 400 nfs_print(vp); 401 else if (!strcmp(ST.f_fstypename, "union")) 402 union_print(vp); 403 (void)printf("\n"); 404 } 405 free(e_vnodebase); 406} 407 408void 409vnode_header() 410{ 411 (void)printf("ADDR TYP VFLAG USE HOLD"); 412} 413 414void 415vnode_print(avnode, vp) 416 struct vnode *avnode; 417 struct vnode *vp; 418{ 419 char *type, flags[16]; 420 char *fp = flags; 421 int flag; 422 423 /* 424 * set type 425 */ 426 switch (vp->v_type) { 427 case VNON: 428 type = "non"; break; 429 case VREG: 430 type = "reg"; break; 431 case VDIR: 432 type = "dir"; break; 433 case VBLK: 434 type = "blk"; break; 435 case VCHR: 436 type = "chr"; break; 437 case VLNK: 438 type = "lnk"; break; 439 case VSOCK: 440 type = "soc"; break; 441 case VFIFO: 442 type = "fif"; break; 443 case VBAD: 444 type = "bad"; break; 445 default: 446 type = "unk"; break; 447 } 448 /* 449 * gather flags 450 */ 451 flag = vp->v_flag; 452 if (flag & VROOT) 453 *fp++ = 'R'; 454 if (flag & VTEXT) 455 *fp++ = 'T'; 456 if (flag & VSYSTEM) 457 *fp++ = 'S'; 458 if (flag & VISTTY) 459 *fp++ = 't'; 460 if (flag & VXLOCK) 461 *fp++ = 'L'; 462 if (flag & VXWANT) 463 *fp++ = 'W'; 464 if (flag & VBWAIT) 465 *fp++ = 'B'; 466 if (flag & VALIASED) 467 *fp++ = 'A'; 468 if (flag & VOBJBUF) 469 *fp++ = 'V'; 470 if (flag & VAGE) 471 *fp++ = 'a'; 472 if (flag & VOLOCK) 473 *fp++ = 'l'; 474 if (flag & VOWANT) 475 *fp++ = 'w'; 476 if (flag == 0) 477 *fp++ = '-'; 478 *fp = '\0'; 479 (void)printf("%8x %s %5s %4d %4d", 480 avnode, type, flags, vp->v_usecount, vp->v_holdcnt); 481} 482 483void 484ufs_header() 485{ 486 (void)printf(" FILEID IFLAG RDEV|SZ"); 487} 488 489int 490ufs_print(vp) 491 struct vnode *vp; 492{ 493 int flag; 494 struct inode inode, *ip = &inode; 495 char flagbuf[16], *flags = flagbuf; 496 char *name; 497 mode_t type; 498 499 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode"); 500 flag = ip->i_flag; 501 if (flag & IN_RENAME) 502 *flags++ = 'R'; 503 if (flag & IN_UPDATE) 504 *flags++ = 'U'; 505 if (flag & IN_ACCESS) 506 *flags++ = 'A'; 507 if (flag & IN_CHANGE) 508 *flags++ = 'C'; 509 if (flag & IN_MODIFIED) 510 *flags++ = 'M'; 511 if (flag & IN_SHLOCK) 512 *flags++ = 'S'; 513 if (flag & IN_EXLOCK) 514 *flags++ = 'E'; 515 if (flag == 0) 516 *flags++ = '-'; 517 *flags = '\0'; 518 519 (void)printf(" %6d %5s", ip->i_number, flagbuf); 520 type = ip->i_mode & S_IFMT; 521 if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) 522 if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL)) 523 (void)printf(" %2d,%-2d", 524 major(ip->i_rdev), minor(ip->i_rdev)); 525 else 526 (void)printf(" %7s", name); 527 else 528 (void)printf(" %7qd", ip->i_size); 529 return (0); 530} 531 532void 533nfs_header() 534{ 535 (void)printf(" FILEID NFLAG RDEV|SZ"); 536} 537 538int 539nfs_print(vp) 540 struct vnode *vp; 541{ 542 struct nfsnode nfsnode, *np = &nfsnode; 543 char flagbuf[16], *flags = flagbuf; 544 int flag; 545 char *name; 546 mode_t type; 547 548 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode"); 549 flag = np->n_flag; 550 if (flag & NFLUSHWANT) 551 *flags++ = 'W'; 552 if (flag & NFLUSHINPROG) 553 *flags++ = 'P'; 554 if (flag & NMODIFIED) 555 *flags++ = 'M'; 556 if (flag & NWRITEERR) 557 *flags++ = 'E'; 558 if (flag & NQNFSNONCACHE) 559 *flags++ = 'X'; 560 if (flag & NQNFSWRITE) 561 *flags++ = 'O'; 562 if (flag & NQNFSEVICTED) 563 *flags++ = 'G'; 564 if (flag == 0) 565 *flags++ = '-'; 566 *flags = '\0'; 567 568#define VT np->n_vattr 569 (void)printf(" %6d %5s", VT.va_fileid, flagbuf); 570 type = VT.va_mode & S_IFMT; 571 if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode)) 572 if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL)) 573 (void)printf(" %2d,%-2d", 574 major(VT.va_rdev), minor(VT.va_rdev)); 575 else 576 (void)printf(" %7s", name); 577 else 578 (void)printf(" %7qd", np->n_size); 579 return (0); 580} 581 582void 583union_header() 584{ 585 (void)printf(" UPPER LOWER"); 586} 587 588int 589union_print(vp) 590 struct vnode *vp; 591{ 592 struct union_node unode, *up = &unode; 593 594 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode"); 595 596 (void)printf(" %8x %8x", up->un_uppervp, up->un_lowervp); 597 return (0); 598} 599 600/* 601 * Given a pointer to a mount structure in kernel space, 602 * read it in and return a usable pointer to it. 603 */ 604struct mount * 605getmnt(maddr) 606 struct mount *maddr; 607{ 608 static struct mtab { 609 struct mtab *next; 610 struct mount *maddr; 611 struct mount mount; 612 } *mhead = NULL; 613 struct mtab *mt; 614 615 for (mt = mhead; mt != NULL; mt = mt->next) 616 if (maddr == mt->maddr) 617 return (&mt->mount); 618 if ((mt = malloc(sizeof(struct mtab))) == NULL) 619 errx(1, "malloc"); 620 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table"); 621 mt->maddr = maddr; 622 mt->next = mhead; 623 mhead = mt; 624 return (&mt->mount); 625} 626 627void 628mount_print(mp) 629 struct mount *mp; 630{ 631 int flags; 632 const char *type; 633 634#define ST mp->mnt_stat 635 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename, 636 ST.f_mntfromname, ST.f_mntonname); 637 if ((flags = mp->mnt_flag)) { 638 int i; 639 const char *sep = " ("; 640 641 for (i = 0; mnt_flags[i].m_flag; i++) { 642 if (flags & mnt_flags[i].m_flag) { 643 (void)printf("%s%s", sep, mnt_flags[i].m_name); 644 flags &= ~mnt_flags[i].m_flag; 645 sep = ","; 646 } 647 } 648 if (flags) 649 (void)printf("%sunknown_flags:%x", sep, flags); 650 (void)printf(")"); 651 } 652 (void)printf("\n"); 653#undef ST 654} 655 656struct e_vnode * 657loadvnodes(avnodes) 658 int *avnodes; 659{ 660 int mib[2]; 661 size_t copysize; 662 struct e_vnode *vnodebase; 663 664 if (memf != NULL) { 665 /* 666 * do it by hand 667 */ 668 return (kinfo_vnodes(avnodes)); 669 } 670 mib[0] = CTL_KERN; 671 mib[1] = KERN_VNODE; 672 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1) 673 err(1, "sysctl: KERN_VNODE"); 674 if ((vnodebase = malloc(copysize)) == NULL) 675 errx(1, "malloc"); 676 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1) 677 err(1, "sysctl: KERN_VNODE"); 678 if (copysize % sizeof(struct e_vnode)) 679 errx(1, "vnode size mismatch"); 680 *avnodes = copysize / sizeof(struct e_vnode); 681 682 return (vnodebase); 683} 684 685/* 686 * simulate what a running kernel does in in kinfo_vnode 687 */ 688struct e_vnode * 689kinfo_vnodes(avnodes) 690 int *avnodes; 691{ 692 struct mntlist mountlist; 693 struct mount *mp, mount, *mp_next; 694 struct vnode *vp, vnode, *vp_next; 695 char *vbuf, *evbuf, *bp; 696 int num, numvnodes; 697 698#define VPTRSZ sizeof(struct vnode *) 699#define VNODESZ sizeof(struct vnode) 700 701 KGET(V_NUMV, numvnodes); 702 if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL) 703 errx(1, "malloc"); 704 bp = vbuf; 705 evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ); 706 KGET(V_MOUNTLIST, mountlist); 707 for (num = 0, mp = mountlist.cqh_first; ; mp = mp_next) { 708 KGET2(mp, &mount, sizeof(mount), "mount entry"); 709 mp_next = mount.mnt_list.cqe_next; 710 for (vp = mount.mnt_vnodelist.lh_first; 711 vp != NULL; vp = vp_next) { 712 KGET2(vp, &vnode, sizeof(vnode), "vnode"); 713 vp_next = vnode.v_mntvnodes.le_next; 714 if ((bp + VPTRSZ + VNODESZ) > evbuf) 715 /* XXX - should realloc */ 716 errx(1, "no more room for vnodes"); 717 memmove(bp, &vp, VPTRSZ); 718 bp += VPTRSZ; 719 memmove(bp, &vnode, VNODESZ); 720 bp += VNODESZ; 721 num++; 722 } 723 if (mp == mountlist.cqh_last) 724 break; 725 } 726 *avnodes = num; 727 return ((struct e_vnode *)vbuf); 728} 729 730char hdr[] = 731" LINE RAW CAN OUT IHWT LWT OHWT LWT COL STATE SESS PGID DISC\n"; 732int ttyspace = 128; 733 734void 735ttymode() 736{ 737 struct tty *tty; 738 739 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL) 740 errx(1, "malloc"); 741#if !defined(hp300) && !defined(mips) 742 if (nl[SCONS].n_type != 0) { 743 (void)printf("1 console\n"); 744 KGET(SCONS, *tty); 745 (void)printf(hdr); 746 ttyprt(&tty[0], 0); 747 } 748#endif 749#ifdef vax 750 if (nl[SNQD].n_type != 0) 751 qdss(); 752 if (nl[SNDZ].n_type != 0) 753 ttytype(tty, "dz", SDZ, SNDZ, 0); 754 if (nl[SNDH].n_type != 0) 755 ttytype(tty, "dh", SDH, SNDH, 0); 756 if (nl[SNDMF].n_type != 0) 757 ttytype(tty, "dmf", SDMF, SNDMF, 0); 758 if (nl[SNDHU].n_type != 0) 759 ttytype(tty, "dhu", SDHU, SNDHU, 0); 760 if (nl[SNDMZ].n_type != 0) 761 ttytype(tty, "dmz", SDMZ, SNDMZ, 0); 762#endif 763#ifdef tahoe 764 if (nl[SNVX].n_type != 0) 765 ttytype(tty, "vx", SVX, SNVX, 0); 766 if (nl[SNMP].n_type != 0) 767 ttytype(tty, "mp", SMP, SNMP, 0); 768#endif 769#ifdef hp300 770 if (nl[SNITE].n_type != 0) 771 ttytype(tty, "ite", SITE, SNITE, 0); 772 if (nl[SNDCA].n_type != 0) 773 ttytype(tty, "dca", SDCA, SNDCA, 0); 774 if (nl[SNDCM].n_type != 0) 775 ttytype(tty, "dcm", SDCM, SNDCM, 0); 776 if (nl[SNDCL].n_type != 0) 777 ttytype(tty, "dcl", SDCL, SNDCL, 0); 778#endif 779#ifdef mips 780 if (nl[SNDC].n_type != 0) 781 ttytype(tty, "dc", SDC, SNDC, 0); 782#endif 783#ifdef __FreeBSD__ 784 if (nl[NSCCONS].n_type != 0) 785 ttytype(tty, "vty", SCCONS, NSCCONS, 0); 786 if (nl[NSIO].n_type != 0) 787 ttytype(tty, "sio", SIO, NSIO, 0); 788 if (nl[NRC].n_type != 0) 789 ttytype(tty, "rc", RC, NRC, 0); 790 if (nl[NCY].n_type != 0) 791 ttytype(tty, "cy", CY, NCY, 0); 792 if (nl[NSI].n_type != 0) 793 ttytype(tty, "si", SI, NSI, 1); 794#endif 795 if (nl[SNPTY].n_type != 0) 796 ttytype(tty, "pty", SPTY, SNPTY, 0); 797} 798 799void 800ttytype(tty, name, type, number, indir) 801 struct tty *tty; 802 char *name; 803 int type, number, indir; 804{ 805 struct tty *tp; 806 int ntty; 807 struct tty **ttyaddr; 808 809 if (tty == NULL) 810 return; 811 KGET(number, ntty); 812 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines"); 813 if (ntty > ttyspace) { 814 ttyspace = ntty; 815 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0) 816 errx(1, "realloc"); 817 } 818 if (indir) { 819 KGET(type, ttyaddr); 820 KGET2(ttyaddr, tty, ntty * sizeof(struct tty), "tty structs"); 821 } else { 822 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs"); 823 } 824 (void)printf(hdr); 825 for (tp = tty; tp < &tty[ntty]; tp++) 826 ttyprt(tp, tp - tty); 827} 828 829struct { 830 int flag; 831 char val; 832} ttystates[] = { 833#ifdef TS_WOPEN 834 { TS_WOPEN, 'W'}, 835#endif 836 { TS_ISOPEN, 'O'}, 837 { TS_CARR_ON, 'C'}, 838#ifdef TS_CONNECTED 839 { TS_CONNECTED, 'c'}, 840#endif 841 { TS_TIMEOUT, 'T'}, 842 { TS_FLUSH, 'F'}, 843 { TS_BUSY, 'B'}, 844#ifdef TS_ASLEEP 845 { TS_ASLEEP, 'A'}, 846#endif 847#ifdef TS_SO_OLOWAT 848 { TS_SO_OLOWAT, 'A'}, 849#endif 850#ifdef TS_SO_OCOMPLETE 851 { TS_SO_OCOMPLETE, 'a'}, 852#endif 853 { TS_XCLUDE, 'X'}, 854 { TS_TTSTOP, 'S'}, 855#ifdef TS_CAR_OFLOW 856 { TS_CAR_OFLOW, 'm'}, 857#endif 858#ifdef TS_CTS_OFLOW 859 { TS_CTS_OFLOW, 'o'}, 860#endif 861#ifdef TS_DSR_OFLOW 862 { TS_DSR_OFLOW, 'd'}, 863#endif 864 { TS_TBLOCK, 'K'}, 865 { TS_ASYNC, 'Y'}, 866 { TS_BKSL, 'D'}, 867 { TS_ERASE, 'E'}, 868 { TS_LNCH, 'L'}, 869 { TS_TYPEN, 'P'}, 870 { TS_CNTTB, 'N'}, 871#ifdef TS_CAN_BYPASS_L_RINT 872 { TS_CAN_BYPASS_L_RINT, 'l'}, 873#endif 874#ifdef TS_SNOOP 875 { TS_SNOOP, 's'}, 876#endif 877#ifdef TS_ZOMBIE 878 { TS_ZOMBIE, 'Z'}, 879#endif 880 { 0, '\0'}, 881}; 882 883void 884ttyprt(tp, line) 885 struct tty *tp; 886 int line; 887{ 888 int i, j; 889 pid_t pgid; 890 char *name, state[20]; 891 892 if (usenumflag || tp->t_dev == 0 || 893 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 894 (void)printf("%7d ", line); 895 else 896 (void)printf("%7s ", name); 897 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 898 (void)printf("%3d %4d %3d %4d %3d %7d ", tp->t_outq.c_cc, 899 tp->t_ihiwat, tp->t_ilowat, tp->t_ohiwat, tp->t_olowat, 900 tp->t_column); 901 for (i = j = 0; ttystates[i].flag; i++) 902 if (tp->t_state&ttystates[i].flag) 903 state[j++] = ttystates[i].val; 904 if (j == 0) 905 state[j++] = '-'; 906 state[j] = '\0'; 907 (void)printf("%-6s %8x", state, (u_long)tp->t_session); 908 pgid = 0; 909 if (tp->t_pgrp != NULL) 910 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); 911 (void)printf("%6d ", pgid); 912 switch (tp->t_line) { 913 case TTYDISC: 914 (void)printf("term\n"); 915 break; 916 case NTTYDISC: 917 (void)printf("ntty\n"); 918 break; 919 case TABLDISC: 920 (void)printf("tab\n"); 921 break; 922 case SLIPDISC: 923 (void)printf("slip\n"); 924 break; 925 case PPPDISC: 926 (void)printf("ppp\n"); 927 break; 928 default: 929 (void)printf("%d\n", tp->t_line); 930 break; 931 } 932} 933 934void 935filemode() 936{ 937 struct file *fp; 938 struct file *addr; 939 char *buf, flagbuf[16], *fbp; 940 int len, maxfile, nfile; 941 static char *dtypes[] = { "???", "inode", "socket" }; 942 943 KGET(FNL_MAXFILE, maxfile); 944 if (totalflag) { 945 KGET(FNL_NFILE, nfile); 946 (void)printf("%3d/%3d files\n", nfile, maxfile); 947 return; 948 } 949 if (getfiles(&buf, &len) == -1) 950 return; 951 /* 952 * Getfiles returns in malloc'd memory a pointer to the first file 953 * structure, and then an array of file structs (whose addresses are 954 * derivable from the previous entry). 955 */ 956 addr = ((struct filelist *)buf)->lh_first; 957 fp = (struct file *)(buf + sizeof(struct filelist)); 958 nfile = (len - sizeof(struct filelist)) / sizeof(struct file); 959 960 (void)printf("%d/%d open files\n", nfile, maxfile); 961 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 962 for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) { 963 if ((unsigned)fp->f_type > DTYPE_SOCKET) 964 continue; 965 (void)printf("%x ", addr); 966 (void)printf("%-8.8s", dtypes[fp->f_type]); 967 fbp = flagbuf; 968 if (fp->f_flag & FREAD) 969 *fbp++ = 'R'; 970 if (fp->f_flag & FWRITE) 971 *fbp++ = 'W'; 972 if (fp->f_flag & FAPPEND) 973 *fbp++ = 'A'; 974#ifdef FSHLOCK /* currently gone */ 975 if (fp->f_flag & FSHLOCK) 976 *fbp++ = 'S'; 977 if (fp->f_flag & FEXLOCK) 978 *fbp++ = 'X'; 979#endif 980 if (fp->f_flag & FASYNC) 981 *fbp++ = 'I'; 982 *fbp = '\0'; 983 (void)printf("%6s %3d", flagbuf, fp->f_count); 984 (void)printf(" %3d", fp->f_msgcount); 985 (void)printf(" %8.1x", fp->f_data); 986 if (fp->f_offset < 0) 987 (void)printf(" %qx\n", fp->f_offset); 988 else 989 (void)printf(" %qd\n", fp->f_offset); 990 } 991 free(buf); 992} 993 994int 995getfiles(abuf, alen) 996 char **abuf; 997 int *alen; 998{ 999 size_t len; 1000 int mib[2]; 1001 char *buf; 1002 1003 /* 1004 * XXX 1005 * Add emulation of KINFO_FILE here. 1006 */ 1007 if (memf != NULL) 1008 errx(1, "files on dead kernel, not implemented"); 1009 1010 mib[0] = CTL_KERN; 1011 mib[1] = KERN_FILE; 1012 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 1013 warn("sysctl: KERN_FILE"); 1014 return (-1); 1015 } 1016 if ((buf = malloc(len)) == NULL) 1017 errx(1, "malloc"); 1018 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 1019 warn("sysctl: KERN_FILE"); 1020 return (-1); 1021 } 1022 *abuf = buf; 1023 *alen = len; 1024 return (0); 1025} 1026 1027/* 1028 * swapmode is based on a program called swapinfo written 1029 * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 1030 */ 1031void 1032swapmode() 1033{ 1034 char *header, *p; 1035 int hlen, nswap, nswdev, dmmax; 1036 int i, div, avail, nfree, npfree, used; 1037 struct swdevt *sw; 1038 long blocksize, *perdev; 1039 struct rlist head; 1040 struct rlisthdr swaplist; 1041 struct rlist *swapptr; 1042 u_long ptr; 1043 1044 KGET(VM_NSWAP, nswap); 1045 KGET(VM_NSWDEV, nswdev); 1046 KGET(VM_DMMAX, dmmax); 1047 KGET1(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist"); 1048 if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || 1049 (perdev = malloc(nswdev * sizeof(*perdev))) == NULL) 1050 errx(1, "malloc"); 1051 KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt"); 1052 KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt"); 1053 1054 /* Count up swap space. */ 1055 nfree = 0; 1056 memset(perdev, 0, nswdev * sizeof(*perdev)); 1057 swapptr = swaplist.rlh_list; 1058 while (swapptr) { 1059 int top, bottom, next_block; 1060 1061 KGET2(swapptr, &head, sizeof(struct rlist), "swapptr"); 1062 1063 top = head.rl_end; 1064 bottom = head.rl_start; 1065 1066 nfree += top - bottom + 1; 1067 1068 /* 1069 * Swap space is split up among the configured disks. 1070 * 1071 * For interleaved swap devices, the first dmmax blocks 1072 * of swap space some from the first disk, the next dmmax 1073 * blocks from the next, and so on up to nswap blocks. 1074 * 1075 * The list of free space joins adjacent free blocks, 1076 * ignoring device boundries. If we want to keep track 1077 * of this information per device, we'll just have to 1078 * extract it ourselves. 1079 */ 1080 while (top / dmmax != bottom / dmmax) { 1081 next_block = ((bottom + dmmax) / dmmax); 1082 perdev[(bottom / dmmax) % nswdev] += 1083 next_block * dmmax - bottom; 1084 bottom = next_block * dmmax; 1085 } 1086 perdev[(bottom / dmmax) % nswdev] += 1087 top - bottom + 1; 1088 1089 swapptr = head.rl_next; 1090 } 1091 1092 header = getbsize(&hlen, &blocksize); 1093 if (!totalflag) 1094 (void)printf("%-11s %*s %8s %8s %8s %s\n", 1095 "Device", hlen, header, 1096 "Used", "Avail", "Capacity", "Type"); 1097 div = blocksize / 512; 1098 avail = npfree = 0; 1099 for (i = 0; i < nswdev; i++) { 1100 int xsize, xfree; 1101 1102 /* 1103 * Don't report statistics for partitions which have not 1104 * yet been activated via swapon(8). 1105 */ 1106 if (!(sw[i].sw_flags & SW_FREED)) 1107 continue; 1108 1109 if (!totalflag) 1110 if (sw[i].sw_dev != NODEV) { 1111 p = devname(sw[i].sw_dev, S_IFBLK); 1112 (void)printf("/dev/%-6s %*d ", 1113 p == NULL ? "??" : p, 1114 hlen, sw[i].sw_nblks / div); 1115 } else 1116 (void)printf("[NFS swap] %*d ", 1117 hlen, sw[i].sw_nblks / div); 1118 1119 /* The first dmmax is never allocated to avoid trashing of 1120 * disklabels 1121 */ 1122 xsize = sw[i].sw_nblks - dmmax; 1123 xfree = perdev[i]; 1124 used = xsize - xfree; 1125 npfree++; 1126 avail += xsize; 1127 if (totalflag) 1128 continue; 1129 (void)printf("%8d %8d %5.0f%% %s\n", 1130 used / div, xfree / div, 1131 (double)used / (double)xsize * 100.0, 1132 (sw[i].sw_flags & SW_SEQUENTIAL) ? 1133 "Sequential" : "Interleaved"); 1134 } 1135 1136 /* 1137 * If only one partition has been set up via swapon(8), we don't 1138 * need to bother with totals. 1139 */ 1140 used = avail - nfree; 1141 free(sw); 1142 free(perdev); 1143 if (totalflag) { 1144 (void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048); 1145 return; 1146 } 1147 if (npfree > 1) { 1148 (void)printf("%-11s %*d %8d %8d %5.0f%%\n", 1149 "Total", hlen, avail / div, used / div, nfree / div, 1150 (double)used / (double)avail * 100.0); 1151 } 1152} 1153