1 /*- 2 * Copyright (c) 1988, 1993 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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#) Copyright (c) 1988, 1993 The Regents of the University of California. All rights reserved. 34 * @(#)fstat.c 8.3 (Berkeley) 5/2/95 35 * $FreeBSD: src/usr.bin/fstat/fstat.c,v 1.21.2.7 2001/11/21 10:49:37 dwmalone Exp $ 36 * $DragonFly: src/usr.bin/fstat/fstat.c,v 1.6 2003/10/04 20:36:44 hmp Exp $ 37 */ 38 39 #define _KERNEL_STRUCTURES 40 41 #include <sys/param.h> 42 #include <sys/time.h> 43 #include <sys/proc.h> 44 #include <sys/user.h> 45 #include <sys/stat.h> 46 #include <sys/vnode.h> 47 #include <sys/socket.h> 48 #include <sys/socketvar.h> 49 #include <sys/domain.h> 50 #include <sys/protosw.h> 51 #include <sys/un.h> 52 #include <sys/unpcb.h> 53 #include <sys/sysctl.h> 54 #include <sys/filedesc.h> 55 #include <sys/queue.h> 56 #include <sys/pipe.h> 57 #include <sys/conf.h> 58 #include <sys/file.h> 59 #include <vfs/ufs/quota.h> 60 #include <vfs/ufs/inode.h> 61 #include <sys/mount.h> 62 #include <nfs/nfsproto.h> 63 #include <nfs/rpcv2.h> 64 #include <nfs/nfs.h> 65 #include <nfs/nfsnode.h> 66 67 68 #include <vm/vm.h> 69 #include <vm/vm_map.h> 70 #include <vm/vm_object.h> 71 72 #include <net/route.h> 73 #include <netinet/in.h> 74 #include <netinet/in_systm.h> 75 #include <netinet/ip.h> 76 #include <netinet/in_pcb.h> 77 78 #include <ctype.h> 79 #include <err.h> 80 #include <fcntl.h> 81 #include <kvm.h> 82 #include <limits.h> 83 #include <nlist.h> 84 #include <paths.h> 85 #include <pwd.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <unistd.h> 90 #include <netdb.h> 91 92 #include "fstat.h" 93 94 #define TEXT -1 95 #define CDIR -2 96 #define RDIR -3 97 #define TRACE -4 98 #define MMAP -5 99 100 DEVS *devs; 101 102 #ifdef notdef 103 struct nlist nl[] = { 104 { "" }, 105 }; 106 #endif 107 108 int fsflg, /* show files on same filesystem as file(s) argument */ 109 pflg, /* show files open by a particular pid */ 110 uflg; /* show files open by a particular (effective) user */ 111 int checkfile; /* true if restricting to particular files or filesystems */ 112 int nflg; /* (numerical) display f.s. and rdev as dev_t */ 113 int vflg; /* display errors in locating kernel data objects etc... */ 114 int mflg; /* include memory-mapped files */ 115 116 117 struct file **ofiles; /* buffer of pointers to file structures */ 118 int maxfiles; 119 #define ALLOC_OFILES(d) \ 120 if ((d) > maxfiles) { \ 121 free(ofiles); \ 122 ofiles = malloc((d) * sizeof(struct file *)); \ 123 if (ofiles == NULL) { \ 124 err(1, NULL); \ 125 } \ 126 maxfiles = (d); \ 127 } 128 129 kvm_t *kd; 130 131 void dofiles(struct kinfo_proc *kp); 132 void dommap(struct kinfo_proc *kp); 133 void vtrans(struct vnode *vp, int i, int flag); 134 int ufs_filestat(struct vnode *vp, struct filestat *fsp); 135 int nfs_filestat(struct vnode *vp, struct filestat *fsp); 136 char *getmnton(struct mount *m); 137 void pipetrans(struct pipe *pi, int i, int flag); 138 void socktrans(struct socket *sock, int i); 139 void getinetproto(int number); 140 int getfname(char *filename); 141 void usage(void); 142 143 144 int 145 main(int argc, char **argv) 146 { 147 register struct passwd *passwd; 148 struct kinfo_proc *p, *plast; 149 int arg, ch, what; 150 char *memf, *nlistf; 151 char buf[_POSIX2_LINE_MAX]; 152 int cnt; 153 154 arg = 0; 155 what = KERN_PROC_ALL; 156 nlistf = memf = NULL; 157 while ((ch = getopt(argc, argv, "fmnp:u:vN:M:")) != -1) 158 switch((char)ch) { 159 case 'f': 160 fsflg = 1; 161 break; 162 case 'M': 163 memf = optarg; 164 break; 165 case 'N': 166 nlistf = optarg; 167 break; 168 case 'm': 169 mflg = 1; 170 break; 171 case 'n': 172 nflg = 1; 173 break; 174 case 'p': 175 if (pflg++) 176 usage(); 177 if (!isdigit(*optarg)) { 178 warnx("-p requires a process id"); 179 usage(); 180 } 181 what = KERN_PROC_PID; 182 arg = atoi(optarg); 183 break; 184 case 'u': 185 if (uflg++) 186 usage(); 187 if (!(passwd = getpwnam(optarg))) 188 errx(1, "%s: unknown uid", optarg); 189 what = KERN_PROC_UID; 190 arg = passwd->pw_uid; 191 break; 192 case 'v': 193 vflg = 1; 194 break; 195 case '?': 196 default: 197 usage(); 198 } 199 200 if (*(argv += optind)) { 201 for (; *argv; ++argv) { 202 if (getfname(*argv)) 203 checkfile = 1; 204 } 205 if (!checkfile) /* file(s) specified, but none accessable */ 206 exit(1); 207 } 208 209 ALLOC_OFILES(256); /* reserve space for file pointers */ 210 211 if (fsflg && !checkfile) { 212 /* -f with no files means use wd */ 213 if (getfname(".") == 0) 214 exit(1); 215 checkfile = 1; 216 } 217 218 /* 219 * Discard setgid privileges if not the running kernel so that bad 220 * guys can't print interesting stuff from kernel memory. 221 */ 222 if (nlistf != NULL || memf != NULL) 223 setgid(getgid()); 224 225 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) 226 errx(1, "%s", buf); 227 #ifdef notdef 228 if (kvm_nlist(kd, nl) != 0) 229 errx(1, "no namelist: %s", kvm_geterr(kd)); 230 #endif 231 if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) 232 errx(1, "%s", kvm_geterr(kd)); 233 if (nflg) 234 printf("%s", 235 "USER CMD PID FD DEV INUM MODE SZ|DV R/W"); 236 else 237 printf("%s", 238 "USER CMD PID FD MOUNT INUM MODE SZ|DV R/W"); 239 if (checkfile && fsflg == 0) 240 printf(" NAME\n"); 241 else 242 putchar('\n'); 243 244 for (plast = &p[cnt]; p < plast; ++p) { 245 if (p->kp_proc.p_stat == SZOMB) 246 continue; 247 dofiles(p); 248 if (mflg) 249 dommap(p); 250 } 251 exit(0); 252 } 253 254 char *Uname, *Comm; 255 int Pid; 256 257 #define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \ 258 switch(i) { \ 259 case TEXT: \ 260 printf(" text"); \ 261 break; \ 262 case CDIR: \ 263 printf(" wd"); \ 264 break; \ 265 case RDIR: \ 266 printf(" root"); \ 267 break; \ 268 case TRACE: \ 269 printf(" tr"); \ 270 break; \ 271 case MMAP: \ 272 printf(" mmap"); \ 273 break; \ 274 default: \ 275 printf(" %4d", i); \ 276 break; \ 277 } 278 279 /* 280 * print open files attributed to this process 281 */ 282 void 283 dofiles(struct kinfo_proc *kp) 284 { 285 int i; 286 struct file file; 287 struct filedesc0 filed0; 288 #define filed filed0.fd_fd 289 struct proc *p = &kp->kp_proc; 290 struct eproc *ep = &kp->kp_eproc; 291 292 Uname = user_from_uid(ep->e_ucred.cr_uid, 0); 293 Pid = p->p_pid; 294 Comm = kp->kp_thread.td_comm; 295 296 if (p->p_fd == NULL) 297 return; 298 if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) { 299 dprintf(stderr, "can't read filedesc at %p for pid %d\n", 300 (void *)p->p_fd, Pid); 301 return; 302 } 303 /* 304 * root directory vnode, if one 305 */ 306 if (filed.fd_rdir) 307 vtrans(filed.fd_rdir, RDIR, FREAD); 308 /* 309 * current working directory vnode 310 */ 311 vtrans(filed.fd_cdir, CDIR, FREAD); 312 /* 313 * ktrace vnode, if one 314 */ 315 if (p->p_tracep) 316 vtrans(p->p_tracep, TRACE, FREAD|FWRITE); 317 /* 318 * text vnode, if one 319 */ 320 if (p->p_textvp) 321 vtrans(p->p_textvp, TEXT, FREAD); 322 /* 323 * open files 324 */ 325 #define FPSIZE (sizeof (struct file *)) 326 ALLOC_OFILES(filed.fd_lastfile+1); 327 if (filed.fd_nfiles > NDFILE) { 328 if (!KVM_READ(filed.fd_ofiles, ofiles, 329 (filed.fd_lastfile+1) * FPSIZE)) { 330 dprintf(stderr, 331 "can't read file structures at %p for pid %d\n", 332 (void *)filed.fd_ofiles, Pid); 333 return; 334 } 335 } else 336 bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE); 337 for (i = 0; i <= filed.fd_lastfile; i++) { 338 if (ofiles[i] == NULL) 339 continue; 340 if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) { 341 dprintf(stderr, "can't read file %d at %p for pid %d\n", 342 i, (void *)ofiles[i], Pid); 343 continue; 344 } 345 if (file.f_type == DTYPE_VNODE) 346 vtrans((struct vnode *)file.f_data, i, file.f_flag); 347 else if (file.f_type == DTYPE_SOCKET) { 348 if (checkfile == 0) 349 socktrans((struct socket *)file.f_data, i); 350 } 351 #ifdef DTYPE_PIPE 352 else if (file.f_type == DTYPE_PIPE) { 353 if (checkfile == 0) 354 pipetrans((struct pipe *)file.f_data, i, 355 file.f_flag); 356 } 357 #endif 358 #ifdef DTYPE_FIFO 359 else if (file.f_type == DTYPE_FIFO) { 360 if (checkfile == 0) 361 vtrans((struct vnode *)file.f_data, i, 362 file.f_flag); 363 } 364 #endif 365 else { 366 dprintf(stderr, 367 "unknown file type %d for file %d of pid %d\n", 368 file.f_type, i, Pid); 369 } 370 } 371 } 372 373 void 374 dommap(struct kinfo_proc *kp) 375 { 376 struct proc *p = &kp->kp_proc; 377 struct vmspace vmspace; 378 vm_map_t map; 379 struct vm_map_entry entry; 380 vm_map_entry_t entryp; 381 struct vm_object object; 382 vm_object_t objp; 383 int prot, fflags; 384 385 if (!KVM_READ(p->p_vmspace, &vmspace, sizeof(vmspace))) { 386 dprintf(stderr, "can't read vmspace at %p for pid %d\n", 387 (void *)p->p_vmspace, Pid); 388 return; 389 } 390 391 map = &vmspace.vm_map; 392 393 for (entryp = map->header.next; entryp != &p->p_vmspace->vm_map.header; 394 entryp = entry.next) { 395 if (!KVM_READ(entryp, &entry, sizeof(entry))) { 396 dprintf(stderr, 397 "can't read vm_map_entry at %p for pid %d\n", 398 (void *)entryp, Pid); 399 return; 400 } 401 402 if (entry.eflags & MAP_ENTRY_IS_SUB_MAP) 403 continue; 404 405 if ((objp = entry.object.vm_object) == NULL) 406 continue; 407 408 for (; objp; objp = object.backing_object) { 409 if (!KVM_READ(objp, &object, sizeof(object))) { 410 dprintf(stderr, 411 "can't read vm_object at %p for pid %d\n", 412 (void *)objp, Pid); 413 return; 414 } 415 } 416 417 prot = entry.protection; 418 fflags = (prot & VM_PROT_READ ? FREAD : 0) | 419 (prot & VM_PROT_WRITE ? FWRITE : 0); 420 421 switch (object.type) { 422 case OBJT_VNODE: 423 vtrans((struct vnode *)object.handle, MMAP, fflags); 424 break; 425 default: 426 break; 427 } 428 } 429 } 430 431 void 432 vtrans(struct vnode *vp, int i, int flag) 433 { 434 struct vnode vn; 435 struct filestat fst; 436 char rw[3], mode[15]; 437 char *badtype = NULL, *filename, *getmnton(); 438 439 filename = badtype = NULL; 440 if (!KVM_READ(vp, &vn, sizeof (struct vnode))) { 441 dprintf(stderr, "can't read vnode at %p for pid %d\n", 442 (void *)vp, Pid); 443 return; 444 } 445 if (vn.v_type == VNON || vn.v_tag == VT_NON) 446 badtype = "none"; 447 else if (vn.v_type == VBAD) 448 badtype = "bad"; 449 else 450 switch (vn.v_tag) { 451 case VT_UFS: 452 if (!ufs_filestat(&vn, &fst)) 453 badtype = "error"; 454 break; 455 case VT_MFS: 456 if (!ufs_filestat(&vn, &fst)) 457 badtype = "error"; 458 break; 459 case VT_NFS: 460 if (!nfs_filestat(&vn, &fst)) 461 badtype = "error"; 462 break; 463 464 case VT_MSDOSFS: 465 if (!msdosfs_filestat(&vn, &fst)) 466 badtype = "error"; 467 break; 468 469 case VT_ISOFS: 470 if (!isofs_filestat(&vn, &fst)) 471 badtype = "error"; 472 break; 473 474 default: { 475 static char unknown[10]; 476 sprintf(badtype = unknown, "?(%x)", vn.v_tag); 477 break;; 478 } 479 } 480 if (checkfile) { 481 int fsmatch = 0; 482 register DEVS *d; 483 484 if (badtype) 485 return; 486 for (d = devs; d != NULL; d = d->next) 487 if (d->fsid == fst.fsid) { 488 fsmatch = 1; 489 if (d->ino == fst.fileid) { 490 filename = d->name; 491 break; 492 } 493 } 494 if (fsmatch == 0 || (filename == NULL && fsflg == 0)) 495 return; 496 } 497 PREFIX(i); 498 if (badtype) { 499 (void)printf(" - - %10s -\n", badtype); 500 return; 501 } 502 if (nflg) 503 (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid)); 504 else 505 (void)printf(" %-8s", getmnton(vn.v_mount)); 506 if (nflg) 507 (void)sprintf(mode, "%o", fst.mode); 508 else 509 strmode(fst.mode, mode); 510 (void)printf(" %6ld %10s", fst.fileid, mode); 511 switch (vn.v_type) { 512 case VBLK: 513 case VCHR: { 514 char *name; 515 516 if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? 517 S_IFCHR : S_IFBLK)) == NULL)) 518 printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev)); 519 else 520 printf(" %6s", name); 521 break; 522 } 523 default: 524 printf(" %6lu", fst.size); 525 } 526 rw[0] = '\0'; 527 if (flag & FREAD) 528 strcat(rw, "r"); 529 if (flag & FWRITE) 530 strcat(rw, "w"); 531 printf(" %2s", rw); 532 if (filename && !fsflg) 533 printf(" %s", filename); 534 putchar('\n'); 535 } 536 537 int 538 ufs_filestat(struct vnode *vp, struct filestat *fsp) 539 { 540 struct inode inode; 541 542 if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) { 543 dprintf(stderr, "can't read inode at %p for pid %d\n", 544 (void *)VTOI(vp), Pid); 545 return 0; 546 } 547 /* 548 * The st_dev from stat(2) is a udev_t. These kernel structures 549 * contain dev_t structures. We need to convert to udev to make 550 * comparisons 551 */ 552 fsp->fsid = dev2udev(inode.i_dev); 553 fsp->fileid = (long)inode.i_number; 554 fsp->mode = (mode_t)inode.i_mode; 555 fsp->size = (u_long)inode.i_size; 556 fsp->rdev = inode.i_rdev; 557 558 return 1; 559 } 560 561 int 562 nfs_filestat(struct vnode *vp, struct filestat *fsp) 563 { 564 struct nfsnode nfsnode; 565 register mode_t mode; 566 567 if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) { 568 dprintf(stderr, "can't read nfsnode at %p for pid %d\n", 569 (void *)VTONFS(vp), Pid); 570 return 0; 571 } 572 fsp->fsid = nfsnode.n_vattr.va_fsid; 573 fsp->fileid = nfsnode.n_vattr.va_fileid; 574 fsp->size = nfsnode.n_size; 575 fsp->rdev = nfsnode.n_vattr.va_rdev; 576 mode = (mode_t)nfsnode.n_vattr.va_mode; 577 switch (vp->v_type) { 578 case VREG: 579 mode |= S_IFREG; 580 break; 581 case VDIR: 582 mode |= S_IFDIR; 583 break; 584 case VBLK: 585 mode |= S_IFBLK; 586 break; 587 case VCHR: 588 mode |= S_IFCHR; 589 break; 590 case VLNK: 591 mode |= S_IFLNK; 592 break; 593 case VSOCK: 594 mode |= S_IFSOCK; 595 break; 596 case VFIFO: 597 mode |= S_IFIFO; 598 break; 599 case VNON: 600 case VBAD: 601 return 0; 602 }; 603 fsp->mode = mode; 604 605 return 1; 606 } 607 608 609 char * 610 getmnton(struct mount *m) 611 { 612 static struct mount mount; 613 static struct mtab { 614 struct mtab *next; 615 struct mount *m; 616 char mntonname[MNAMELEN]; 617 } *mhead = NULL; 618 register struct mtab *mt; 619 620 for (mt = mhead; mt != NULL; mt = mt->next) 621 if (m == mt->m) 622 return (mt->mntonname); 623 if (!KVM_READ(m, &mount, sizeof(struct mount))) { 624 warnx("can't read mount table at %p", (void *)m); 625 return (NULL); 626 } 627 if ((mt = malloc(sizeof (struct mtab))) == NULL) 628 err(1, NULL); 629 mt->m = m; 630 bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 631 mt->next = mhead; 632 mhead = mt; 633 return (mt->mntonname); 634 } 635 636 void 637 pipetrans(struct pipe *pi, int i, int flag) 638 { 639 struct pipe pip; 640 char rw[3]; 641 642 PREFIX(i); 643 644 /* fill in socket */ 645 if (!KVM_READ(pi, &pip, sizeof(struct pipe))) { 646 dprintf(stderr, "can't read pipe at %p\n", (void *)pi); 647 goto bad; 648 } 649 650 printf("* pipe %8lx <-> %8lx", (u_long)pi, (u_long)pip.pipe_peer); 651 printf(" %6d", (int)pip.pipe_buffer.cnt); 652 rw[0] = '\0'; 653 if (flag & FREAD) 654 strcat(rw, "r"); 655 if (flag & FWRITE) 656 strcat(rw, "w"); 657 printf(" %2s", rw); 658 putchar('\n'); 659 return; 660 661 bad: 662 printf("* error\n"); 663 } 664 665 void 666 socktrans(struct socket *sock, int i) 667 { 668 static char *stypename[] = { 669 "unused", /* 0 */ 670 "stream", /* 1 */ 671 "dgram", /* 2 */ 672 "raw", /* 3 */ 673 "rdm", /* 4 */ 674 "seqpak" /* 5 */ 675 }; 676 #define STYPEMAX 5 677 struct socket so; 678 struct protosw proto; 679 struct domain dom; 680 struct inpcb inpcb; 681 struct unpcb unpcb; 682 int len; 683 char dname[32], *strcpy(); 684 685 PREFIX(i); 686 687 /* fill in socket */ 688 if (!KVM_READ(sock, &so, sizeof(struct socket))) { 689 dprintf(stderr, "can't read sock at %p\n", (void *)sock); 690 goto bad; 691 } 692 693 /* fill in protosw entry */ 694 if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) { 695 dprintf(stderr, "can't read protosw at %p", 696 (void *)so.so_proto); 697 goto bad; 698 } 699 700 /* fill in domain */ 701 if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) { 702 dprintf(stderr, "can't read domain at %p\n", 703 (void *)proto.pr_domain); 704 goto bad; 705 } 706 707 if ((len = kvm_read(kd, (u_long)dom.dom_name, dname, 708 sizeof(dname) - 1)) < 0) { 709 dprintf(stderr, "can't read domain name at %p\n", 710 (void *)dom.dom_name); 711 dname[0] = '\0'; 712 } 713 else 714 dname[len] = '\0'; 715 716 if ((u_short)so.so_type > STYPEMAX) 717 printf("* %s ?%d", dname, so.so_type); 718 else 719 printf("* %s %s", dname, stypename[so.so_type]); 720 721 /* 722 * protocol specific formatting 723 * 724 * Try to find interesting things to print. For tcp, the interesting 725 * thing is the address of the tcpcb, for udp and others, just the 726 * inpcb (socket pcb). For unix domain, its the address of the socket 727 * pcb and the address of the connected pcb (if connected). Otherwise 728 * just print the protocol number and address of the socket itself. 729 * The idea is not to duplicate netstat, but to make available enough 730 * information for further analysis. 731 */ 732 switch(dom.dom_family) { 733 case AF_INET: 734 case AF_INET6: 735 getinetproto(proto.pr_protocol); 736 if (proto.pr_protocol == IPPROTO_TCP ) { 737 if (so.so_pcb) { 738 if (kvm_read(kd, (u_long)so.so_pcb, 739 (char *)&inpcb, sizeof(struct inpcb)) 740 != sizeof(struct inpcb)) { 741 dprintf(stderr, 742 "can't read inpcb at %p\n", 743 (void *)so.so_pcb); 744 goto bad; 745 } 746 printf(" %lx", (u_long)inpcb.inp_ppcb); 747 } 748 } 749 else if (so.so_pcb) 750 printf(" %lx", (u_long)so.so_pcb); 751 break; 752 case AF_UNIX: 753 /* print address of pcb and connected pcb */ 754 if (so.so_pcb) { 755 printf(" %lx", (u_long)so.so_pcb); 756 if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb, 757 sizeof(struct unpcb)) != sizeof(struct unpcb)){ 758 dprintf(stderr, "can't read unpcb at %p\n", 759 (void *)so.so_pcb); 760 goto bad; 761 } 762 if (unpcb.unp_conn) { 763 char shoconn[4], *cp; 764 765 cp = shoconn; 766 if (!(so.so_state & SS_CANTRCVMORE)) 767 *cp++ = '<'; 768 *cp++ = '-'; 769 if (!(so.so_state & SS_CANTSENDMORE)) 770 *cp++ = '>'; 771 *cp = '\0'; 772 printf(" %s %lx", shoconn, 773 (u_long)unpcb.unp_conn); 774 } 775 } 776 break; 777 default: 778 /* print protocol number and socket address */ 779 printf(" %d %lx", proto.pr_protocol, (u_long)sock); 780 } 781 printf("\n"); 782 return; 783 bad: 784 printf("* error\n"); 785 } 786 787 788 /* 789 * Read the specinfo structure in the kernel (as pointed to by a dev_t) 790 * in order to work out the associated udev_t 791 */ 792 udev_t 793 dev2udev(dev_t dev) 794 { 795 struct specinfo si; 796 797 if (KVM_READ(dev, &si, sizeof si)) { 798 return si.si_udev; 799 } else { 800 dprintf(stderr, "can't convert dev_t %x to a udev_t\n", dev); 801 return -1; 802 } 803 } 804 805 /* 806 * getinetproto -- 807 * print name of protocol number 808 */ 809 void 810 getinetproto(int number) 811 { 812 static int isopen; 813 register struct protoent *pe; 814 815 if (!isopen) 816 setprotoent(++isopen); 817 if ((pe = getprotobynumber(number)) != NULL) 818 printf(" %s", pe->p_name); 819 else 820 printf(" %d", number); 821 } 822 823 int 824 getfname(char *filename) 825 { 826 struct stat statbuf; 827 DEVS *cur; 828 829 if (stat(filename, &statbuf)) { 830 warn("%s", filename); 831 return(0); 832 } 833 if ((cur = malloc(sizeof(DEVS))) == NULL) 834 err(1, NULL); 835 cur->next = devs; 836 devs = cur; 837 838 cur->ino = statbuf.st_ino; 839 cur->fsid = statbuf.st_dev; 840 cur->name = filename; 841 return(1); 842 } 843 844 void 845 usage(void) 846 { 847 (void)fprintf(stderr, 848 "usage: fstat [-fmnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n"); 849 exit(1); 850 } 851