|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1988 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)fstat.c 5.25 (Berkeley) 6/29/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* ! 31: * fstat ! 32: */ ! 33: #include <machine/pte.h> ! 34: ! 35: #include <sys/param.h> ! 36: #include <sys/user.h> ! 37: #include <sys/proc.h> ! 38: #include <sys/text.h> ! 39: #include <sys/stat.h> ! 40: #include <sys/time.h> ! 41: #include <sys/vnode.h> ! 42: #include <sys/socket.h> ! 43: #include <sys/socketvar.h> ! 44: #include <sys/domain.h> ! 45: #include <sys/protosw.h> ! 46: #include <sys/unpcb.h> ! 47: #include <sys/vmmac.h> ! 48: #define KERNEL ! 49: #define NFS ! 50: #include <sys/file.h> ! 51: #include <sys/mount.h> ! 52: #include <ufs/quota.h> ! 53: #include <ufs/inode.h> ! 54: #include <nfs/nfsv2.h> ! 55: #include <nfs/nfs.h> ! 56: #include <nfs/nfsnode.h> ! 57: #undef KERNEL ! 58: ! 59: #include <net/route.h> ! 60: #include <netinet/in.h> ! 61: #include <netinet/in_systm.h> ! 62: #include <netinet/ip.h> ! 63: #include <netinet/in_pcb.h> ! 64: ! 65: #include <kvm.h> ! 66: #include <paths.h> ! 67: #include <ctype.h> ! 68: #include <nlist.h> ! 69: #include <pwd.h> ! 70: #include <string.h> ! 71: #include <stdio.h> ! 72: ! 73: #define TEXT -1 ! 74: #define CDIR -2 ! 75: #define RDIR -3 ! 76: #define TRACE -4 ! 77: ! 78: typedef struct devs { ! 79: struct devs *next; ! 80: long fsid; ! 81: ino_t ino; ! 82: char *name; ! 83: } DEVS; ! 84: DEVS *devs; ! 85: ! 86: struct filestat { ! 87: long fsid; ! 88: long fileid; ! 89: mode_t mode; ! 90: u_long size; ! 91: dev_t rdev; ! 92: }; ! 93: ! 94: #ifdef notdef ! 95: struct nlist nl[] = { ! 96: { "" }, ! 97: }; ! 98: #endif ! 99: ! 100: int fsflg, /* show files on same filesystem as file(s) argument */ ! 101: pflg, /* show files open by a particular pid */ ! 102: uflg; /* show files open by a particular (effective) user */ ! 103: int checkfile; /* true if restricting to particular files or filesystems */ ! 104: int nflg; /* (numerical) display f.s. and rdev as dev_t */ ! 105: int vflg; /* display errors in locating kernel data objects etc... */ ! 106: ! 107: #define dprintf if (vflg) fprintf ! 108: ! 109: extern int errno; ! 110: off_t lseek(); ! 111: ! 112: main(argc, argv) ! 113: int argc; ! 114: char **argv; ! 115: { ! 116: register struct passwd *passwd; ! 117: int what = KINFO_PROC_ALL, arg = 0; ! 118: struct passwd *getpwnam(), *getpwuid(); ! 119: struct proc *p; ! 120: extern char *optarg; ! 121: extern int optind; ! 122: int ch; ! 123: char *malloc(); ! 124: ! 125: ! 126: while ((ch = getopt(argc, argv, "p:u:fnv")) != EOF) ! 127: switch((char)ch) { ! 128: case 'p': ! 129: if (pflg++) ! 130: usage(); ! 131: if (!isdigit(*optarg)) { ! 132: fputs("fstat: -p option requires a process id.\n", stderr); ! 133: usage(); ! 134: } ! 135: what = KINFO_PROC_PID; ! 136: arg = atoi(optarg); ! 137: break; ! 138: case 'u': ! 139: if (uflg++) ! 140: usage(); ! 141: if (!(passwd = getpwnam(optarg))) { ! 142: fprintf(stderr, "%s: unknown uid\n", ! 143: optarg); ! 144: exit(1); ! 145: } ! 146: what = KINFO_PROC_UID; ! 147: arg = passwd->pw_uid; ! 148: break; ! 149: case 'f': ! 150: fsflg++; ! 151: break; ! 152: case 'n': ! 153: nflg++; ! 154: break; ! 155: case 'v': ! 156: vflg++; ! 157: break; ! 158: case '?': ! 159: default: ! 160: usage(); ! 161: } ! 162: ! 163: if (*(argv += optind)) { ! 164: for (; *argv; ++argv) { ! 165: if (getfname(*argv)) ! 166: checkfile = 1; ! 167: } ! 168: if (!checkfile) /* file(s) specified, but none accessable */ ! 169: exit(1); ! 170: } ! 171: if (fsflg && !checkfile) { ! 172: /* -f with no files means use wd */ ! 173: if (getfname(".") == 0) ! 174: exit(1); ! 175: checkfile = 1; ! 176: } ! 177: ! 178: /* modify the following to make work on dead kernels */ ! 179: if (kvm_openfiles(NULL, NULL, NULL) == -1) { ! 180: fprintf(stderr, "fstat: %s\n", kvm_geterr()); ! 181: exit(1); ! 182: } ! 183: #ifdef notdef ! 184: if (kvm_nlist(nl) != 0) { ! 185: fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr()); ! 186: exit(1); ! 187: } ! 188: #endif ! 189: if (kvm_getprocs(what, arg) == -1) { ! 190: fprintf(stderr, "fstat: %s\n", kvm_geterr()); ! 191: exit(1); ! 192: } ! 193: if (nflg) ! 194: fputs("USER CMD PID FD DEV INUM MODE SZ|DV", stdout); ! 195: else ! 196: fputs("USER CMD PID FD MOUNT INUM MODE SZ|DV", stdout); ! 197: if (checkfile && fsflg == 0) ! 198: fputs(" NAME\n", stdout); ! 199: else ! 200: putchar('\n'); ! 201: ! 202: while ((p = kvm_nextproc()) != NULL) { ! 203: if (p->p_stat == SZOMB) ! 204: continue; ! 205: dofiles(p); ! 206: } ! 207: exit(0); ! 208: } ! 209: ! 210: char *Uname, *Comm; ! 211: int Pid; ! 212: ! 213: #define PREFIX(i) printf("%-8.8s %-8.8s %5d", Uname, Comm, Pid); \ ! 214: switch(i) { \ ! 215: case TEXT: \ ! 216: fputs(" text", stdout); \ ! 217: break; \ ! 218: case CDIR: \ ! 219: fputs(" wd", stdout); \ ! 220: break; \ ! 221: case RDIR: \ ! 222: fputs(" root", stdout); \ ! 223: break; \ ! 224: case TRACE: \ ! 225: fputs(" tr", stdout); \ ! 226: break; \ ! 227: default: \ ! 228: printf(" %4d", i); \ ! 229: break; \ ! 230: } ! 231: ! 232: /* ! 233: * print open files attributed to this process ! 234: */ ! 235: dofiles(p) ! 236: struct proc *p; ! 237: { ! 238: int i; ! 239: struct file file; ! 240: struct user *up = kvm_getu(p); ! 241: struct vnode *xvptr; ! 242: extern char *user_from_uid(); ! 243: ! 244: Uname = user_from_uid(p->p_uid, 0); ! 245: Pid = p->p_pid; ! 246: Comm = p->p_comm; ! 247: ! 248: if (up == NULL) { ! 249: dprintf(stderr, "can't read u for pid %d\n", Pid); ! 250: return; ! 251: } ! 252: /* ! 253: * root directory vnode, if one ! 254: */ ! 255: if (up->u_rdir) ! 256: vtrans(up->u_rdir, RDIR); ! 257: /* ! 258: * text vnode ! 259: */ ! 260: if (p->p_textp && ! 261: kvm_read(&(p->p_textp->x_vptr), &xvptr, ! 262: sizeof (struct vnode *)) == sizeof (struct vnode *) && ! 263: xvptr != NULL) ! 264: vtrans(xvptr, TEXT); ! 265: /* ! 266: * current working directory vnode ! 267: */ ! 268: vtrans(up->u_cdir, CDIR); ! 269: /* ! 270: * ktrace vnode, if one ! 271: */ ! 272: if (p->p_tracep) ! 273: vtrans(p->p_tracep, TRACE); ! 274: /* ! 275: * open files ! 276: */ ! 277: for (i = 0; i <= up->u_lastfile; i++) { ! 278: if (up->u_ofile[i] == 0) ! 279: continue; ! 280: if (kvm_read(up->u_ofile[i], &file, sizeof (struct file)) != ! 281: sizeof (struct file)) { ! 282: dprintf(stderr, "can't read file %d for pid %d\n", ! 283: i, Pid); ! 284: continue; ! 285: } ! 286: if (file.f_type == DTYPE_VNODE) ! 287: vtrans((struct vnode *)file.f_data, i); ! 288: else if (file.f_type == DTYPE_SOCKET && checkfile == 0) ! 289: socktrans((struct socket *)file.f_data, i); ! 290: else { ! 291: dprintf(stderr, ! 292: "unknown file type %d for file %d of pid %d\n", ! 293: file.f_type, i, Pid); ! 294: } ! 295: } ! 296: } ! 297: ! 298: vtrans(vp, i) ! 299: struct vnode *vp; ! 300: { ! 301: struct vnode vn; ! 302: struct filestat fst; ! 303: char *filename = NULL; ! 304: char *badtype = NULL; ! 305: char *getmnton(); ! 306: extern char *devname(); ! 307: char mode[15]; ! 308: ! 309: if (kvm_read((off_t)vp, &vn, sizeof (struct vnode)) != ! 310: sizeof (struct vnode)) { ! 311: dprintf(stderr, "can't read vnode at %x for pid %d\n", ! 312: vp, Pid); ! 313: return; ! 314: } ! 315: if (vn.v_type == VNON || vn.v_tag == VT_NON) ! 316: badtype = "none"; ! 317: else if (vn.v_type == VBAD) ! 318: badtype = "bad"; ! 319: else ! 320: switch (vn.v_tag) { ! 321: case VT_UFS: ! 322: ufs_filestat(&vn, &fst); ! 323: break; ! 324: case VT_MFS: ! 325: ufs_filestat(&vn, &fst); ! 326: break; ! 327: case VT_NFS: ! 328: nfs_filestat(&vn, &fst); ! 329: break; ! 330: default: { ! 331: static char unknown[10]; ! 332: sprintf(badtype = unknown, "?(%x)", vn.v_tag); ! 333: break;; ! 334: } ! 335: } ! 336: if (checkfile) { ! 337: int fsmatch = 0; ! 338: register DEVS *d; ! 339: ! 340: if (badtype) ! 341: return; ! 342: for (d = devs; d != NULL; d = d->next) ! 343: if (d->fsid == fst.fsid) { ! 344: fsmatch = 1; ! 345: if (d->ino == fst.fileid) { ! 346: filename = d->name; ! 347: break; ! 348: } ! 349: } ! 350: if (fsmatch == 0 || (filename == NULL && fsflg == 0)) ! 351: return; ! 352: } ! 353: PREFIX(i); ! 354: if (badtype) { ! 355: (void)printf(" - - %10s -\n", badtype); ! 356: return; ! 357: } ! 358: if (nflg) ! 359: (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid)); ! 360: else ! 361: (void)printf(" %-8s", getmnton(vn.v_mount)); ! 362: if (nflg) ! 363: (void)sprintf(mode, "%o", fst.mode); ! 364: else ! 365: strmode(fst.mode, mode); ! 366: (void)printf(" %6d %10s", fst.fileid, mode); ! 367: switch (vn.v_type) { ! 368: case VBLK: ! 369: case VCHR: { ! 370: char *name; ! 371: ! 372: if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? ! 373: S_IFCHR : S_IFBLK)) == NULL)) ! 374: printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev)); ! 375: else ! 376: printf(" %6s", name); ! 377: break; ! 378: } ! 379: default: ! 380: printf(" %6d", fst.size); ! 381: } ! 382: if (filename && !fsflg) ! 383: printf(" %s", filename); ! 384: ! 385: putchar('\n'); ! 386: } ! 387: ! 388: ufs_filestat(vp, fsp) ! 389: struct vnode *vp; ! 390: struct filestat *fsp; ! 391: { ! 392: struct inode *ip = VTOI(vp); ! 393: ! 394: fsp->fsid = ip->i_dev & 0xffff; ! 395: fsp->fileid = (long)ip->i_number; ! 396: fsp->mode = (mode_t)ip->i_mode; ! 397: fsp->size = (u_long)ip->i_size; ! 398: fsp->rdev = ip->i_rdev; ! 399: } ! 400: ! 401: nfs_filestat(vp, fsp) ! 402: struct vnode *vp; ! 403: struct filestat *fsp; ! 404: { ! 405: register struct nfsnode *np = VTONFS(vp); ! 406: register mode_t mode; ! 407: ! 408: fsp->fsid = np->n_vattr.va_fsid; ! 409: fsp->fileid = np->n_vattr.va_fileid; ! 410: fsp->size = np->n_size; ! 411: fsp->rdev = np->n_vattr.va_rdev; ! 412: mode = (mode_t)np->n_vattr.va_mode; ! 413: switch (vp->v_type) { ! 414: case VREG: ! 415: mode |= S_IFREG; ! 416: break; ! 417: case VDIR: ! 418: mode |= S_IFDIR; ! 419: break; ! 420: case VBLK: ! 421: mode |= S_IFBLK; ! 422: break; ! 423: case VCHR: ! 424: mode |= S_IFCHR; ! 425: break; ! 426: case VLNK: ! 427: mode |= S_IFLNK; ! 428: break; ! 429: case VSOCK: ! 430: mode |= S_IFSOCK; ! 431: break; ! 432: case VFIFO: ! 433: mode |= S_IFIFO; ! 434: break; ! 435: }; ! 436: fsp->mode = mode; ! 437: } ! 438: ! 439: ! 440: char * ! 441: getmnton(m) ! 442: struct mount *m; ! 443: { ! 444: static struct mount mount; ! 445: static struct mtab { ! 446: struct mtab *next; ! 447: struct mount *m; ! 448: char mntonname[MNAMELEN]; ! 449: } *mhead = NULL; ! 450: register struct mtab *mt; ! 451: ! 452: for (mt = mhead; mt != NULL; mt = mt->next) ! 453: if (m == mt->m) ! 454: return (mt->mntonname); ! 455: if (kvm_read((off_t)m, &mount, sizeof(struct mount)) != ! 456: sizeof(struct mount)) { ! 457: fprintf(stderr, "can't read mount table at %x\n", m); ! 458: return (NULL); ! 459: } ! 460: if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) { ! 461: fprintf(stderr, "out of memory\n"); ! 462: exit(1); ! 463: } ! 464: mt->m = m; ! 465: bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); ! 466: mt->next = mhead; ! 467: mhead = mt; ! 468: return (mt->mntonname); ! 469: } ! 470: ! 471: socktrans(sock, i) ! 472: struct socket *sock; ! 473: { ! 474: static char *stypename[] = { ! 475: "unused", /* 0 */ ! 476: "stream", /* 1 */ ! 477: "dgram", /* 2 */ ! 478: "raw", /* 3 */ ! 479: "rdm", /* 4 */ ! 480: "seqpak" /* 5 */ ! 481: }; ! 482: #define STYPEMAX 5 ! 483: struct socket so; ! 484: struct protosw proto; ! 485: struct domain dom; ! 486: struct inpcb inpcb; ! 487: struct unpcb unpcb; ! 488: int len; ! 489: char dname[32], *strcpy(); ! 490: ! 491: PREFIX(i); ! 492: ! 493: /* fill in socket */ ! 494: if (kvm_read((off_t)sock, (char *)&so, sizeof(struct socket)) ! 495: != sizeof(struct socket)) { ! 496: dprintf(stderr, "can't read sock at %x\n", sock); ! 497: goto bad; ! 498: } ! 499: ! 500: /* fill in protosw entry */ ! 501: if (kvm_read((off_t)so.so_proto, (char *)&proto, sizeof(struct protosw)) ! 502: != sizeof(struct protosw)) { ! 503: dprintf(stderr, "can't read protosw at %x", so.so_proto); ! 504: goto bad; ! 505: } ! 506: ! 507: /* fill in domain */ ! 508: if (kvm_read((off_t)proto.pr_domain, (char *)&dom, sizeof(struct domain)) ! 509: != sizeof(struct domain)) { ! 510: dprintf(stderr, "can't read domain at %x\n", proto.pr_domain); ! 511: goto bad; ! 512: } ! 513: ! 514: /* ! 515: * grab domain name ! 516: * kludge "internet" --> "inet" for brevity ! 517: */ ! 518: if (dom.dom_family == AF_INET) ! 519: strcpy(dname, "inet"); ! 520: else { ! 521: if ((len = kvm_read((off_t)dom.dom_name, dname, sizeof(dname) - 1)) < 0) { ! 522: dprintf(stderr, "can't read domain name at %x\n", ! 523: dom.dom_name); ! 524: dname[0] = '\0'; ! 525: } ! 526: else ! 527: dname[len] = '\0'; ! 528: } ! 529: ! 530: if ((u_short)so.so_type > STYPEMAX) ! 531: printf("* %s ?%d", dname, so.so_type); ! 532: else ! 533: printf("* %s %s", dname, stypename[so.so_type]); ! 534: ! 535: /* ! 536: * protocol specific formatting ! 537: * ! 538: * Try to find interesting things to print. For tcp, the interesting ! 539: * thing is the address of the tcpcb, for udp and others, just the ! 540: * inpcb (socket pcb). For unix domain, its the address of the socket ! 541: * pcb and the address of the connected pcb (if connected). Otherwise ! 542: * just print the protocol number and address of the socket itself. ! 543: * The idea is not to duplicate netstat, but to make available enough ! 544: * information for further analysis. ! 545: */ ! 546: switch(dom.dom_family) { ! 547: case AF_INET: ! 548: getinetproto(proto.pr_protocol); ! 549: if (proto.pr_protocol == IPPROTO_TCP ) { ! 550: if (so.so_pcb) { ! 551: if (kvm_read((off_t)so.so_pcb, (char *)&inpcb, sizeof(struct inpcb)) ! 552: != sizeof(struct inpcb)){ ! 553: dprintf(stderr, ! 554: "can't read inpcb at %x\n", so.so_pcb); ! 555: goto bad; ! 556: } ! 557: printf(" %x", (int)inpcb.inp_ppcb); ! 558: } ! 559: } ! 560: else if (so.so_pcb) ! 561: printf(" %x", (int)so.so_pcb); ! 562: break; ! 563: case AF_UNIX: ! 564: /* print address of pcb and connected pcb */ ! 565: if (so.so_pcb) { ! 566: printf(" %x", (int)so.so_pcb); ! 567: if (kvm_read((off_t)so.so_pcb, (char *)&unpcb, sizeof(struct unpcb)) ! 568: != sizeof(struct unpcb)){ ! 569: dprintf(stderr, "can't read unpcb at %x\n", ! 570: so.so_pcb); ! 571: goto bad; ! 572: } ! 573: if (unpcb.unp_conn) { ! 574: char shoconn[4], *cp; ! 575: ! 576: cp = shoconn; ! 577: if (!(so.so_state & SS_CANTRCVMORE)) ! 578: *cp++ = '<'; ! 579: *cp++ = '-'; ! 580: if (!(so.so_state & SS_CANTSENDMORE)) ! 581: *cp++ = '>'; ! 582: *cp = '\0'; ! 583: printf(" %s %x", shoconn, ! 584: (int)unpcb.unp_conn); ! 585: } ! 586: } ! 587: break; ! 588: default: ! 589: /* print protocol number and socket address */ ! 590: printf(" %d %x", proto.pr_protocol, (int)sock); ! 591: } ! 592: printf("\n"); ! 593: return; ! 594: bad: ! 595: printf("* error\n"); ! 596: } ! 597: ! 598: /* ! 599: * getinetproto -- ! 600: * print name of protocol number ! 601: */ ! 602: getinetproto(number) ! 603: int number; ! 604: { ! 605: char *cp; ! 606: ! 607: switch(number) { ! 608: case IPPROTO_IP: ! 609: cp = "ip"; break; ! 610: case IPPROTO_ICMP: ! 611: cp ="icmp"; break; ! 612: case IPPROTO_GGP: ! 613: cp ="ggp"; break; ! 614: case IPPROTO_TCP: ! 615: cp ="tcp"; break; ! 616: case IPPROTO_EGP: ! 617: cp ="egp"; break; ! 618: case IPPROTO_PUP: ! 619: cp ="pup"; break; ! 620: case IPPROTO_UDP: ! 621: cp ="udp"; break; ! 622: case IPPROTO_IDP: ! 623: cp ="idp"; break; ! 624: case IPPROTO_RAW: ! 625: cp ="raw"; break; ! 626: default: ! 627: printf(" %d", number); ! 628: return; ! 629: } ! 630: printf(" %s", cp); ! 631: } ! 632: ! 633: getfname(filename) ! 634: char *filename; ! 635: { ! 636: struct stat statbuf; ! 637: DEVS *cur; ! 638: char *malloc(); ! 639: ! 640: if (stat(filename, &statbuf)) { ! 641: fprintf(stderr, "fstat: %s: %s\n", strerror(errno), ! 642: filename); ! 643: return(0); ! 644: } ! 645: if ((cur = (DEVS *)malloc(sizeof(DEVS))) == NULL) { ! 646: fprintf(stderr, "fstat: out of space.\n"); ! 647: exit(1); ! 648: } ! 649: cur->next = devs; ! 650: devs = cur; ! 651: ! 652: cur->ino = statbuf.st_ino; ! 653: cur->fsid = statbuf.st_dev & 0xffff; ! 654: cur->name = filename; ! 655: return(1); ! 656: } ! 657: ! 658: usage() ! 659: { ! 660: (void)fprintf(stderr, ! 661: "usage: fstat [-u user] [-p pid] [filename ...]\n"); ! 662: exit(1); ! 663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.