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