fstat.c revision 146466
1179055Sjfv/*- 2171384Sjfv * Copyright (c) 1988, 1993 3320897Serj * The Regents of the University of California. All rights reserved. 4171384Sjfv * 5320897Serj * Redistribution and use in source and binary forms, with or without 6320897Serj * modification, are permitted provided that the following conditions 7171384Sjfv * are met: 8320897Serj * 1. Redistributions of source code must retain the above copyright 9320897Serj * notice, this list of conditions and the following disclaimer. 10171384Sjfv * 2. Redistributions in binary form must reproduce the above copyright 11320897Serj * notice, this list of conditions and the following disclaimer in the 12320897Serj * documentation and/or other materials provided with the distribution. 13320897Serj * 3. All advertising materials mentioning features or use of this software 14171384Sjfv * must display the following acknowledgement: 15320897Serj * This product includes software developed by the University of 16320897Serj * California, Berkeley and its contributors. 17320897Serj * 4. Neither the name of the University nor the names of its contributors 18171384Sjfv * may be used to endorse or promote products derived from this software 19320897Serj * without specific prior written permission. 20171384Sjfv * 21320897Serj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22320897Serj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23320897Serj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24320897Serj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25320897Serj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26320897Serj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27320897Serj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28320897Serj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29171384Sjfv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30171384Sjfv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31171384Sjfv * SUCH DAMAGE. 32179055Sjfv */ 33179055Sjfv 34171384Sjfv#ifndef lint 35171384Sjfvstatic const char copyright[] = 36171384Sjfv"@(#) Copyright (c) 1988, 1993\n\ 37171384Sjfv The Regents of the University of California. All rights reserved.\n"; 38292674Ssbruno#endif /* not lint */ 39292674Ssbruno 40282289Serj#ifndef lint 41292674Ssbruno#if 0 42282289Serjstatic char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95"; 43282289Serj#endif 44282289Serj#endif /* not lint */ 45282289Serj#include <sys/cdefs.h> 46282289Serj__FBSDID("$FreeBSD: head/usr.bin/fstat/fstat.c 146466 2005-05-21 09:55:10Z ru $"); 47282289Serj 48282289Serj#include <sys/param.h> 49282289Serj#include <sys/time.h> 50282289Serj#include <sys/proc.h> 51282289Serj#include <sys/user.h> 52282289Serj#include <sys/stat.h> 53282289Serj#include <sys/vnode.h> 54282289Serj#include <sys/socket.h> 55282289Serj#include <sys/socketvar.h> 56320897Serj#include <sys/domain.h> 57320897Serj#include <sys/protosw.h> 58320897Serj#include <sys/un.h> 59320897Serj#include <sys/unpcb.h> 60171384Sjfv#include <sys/sysctl.h> 61251964Sjfv#include <sys/filedesc.h> 62251964Sjfv#include <sys/queue.h> 63251964Sjfv#define _KERNEL 64251964Sjfv#include <sys/pipe.h> 65251964Sjfv#include <sys/conf.h> 66251964Sjfv#include <sys/file.h> 67251964Sjfv#include <sys/mount.h> 68251964Sjfv#include <ufs/ufs/quota.h> 69251964Sjfv#include <ufs/ufs/inode.h> 70251964Sjfv#include <fs/devfs/devfs.h> 71251964Sjfv#undef _KERNEL 72251964Sjfv#include <nfs/nfsproto.h> 73251964Sjfv#include <nfs/rpcv2.h> 74171384Sjfv#include <nfsclient/nfs.h> 75171384Sjfv#include <nfsclient/nfsnode.h> 76171384Sjfv 77171384Sjfv 78171384Sjfv#include <vm/vm.h> 79171384Sjfv#include <vm/vm_map.h> 80171384Sjfv#include <vm/vm_object.h> 81171384Sjfv 82171384Sjfv#include <net/route.h> 83185352Sjfv#include <netinet/in.h> 84171384Sjfv#include <netinet/in_systm.h> 85171384Sjfv#include <netinet/ip.h> 86171384Sjfv#include <netinet/in_pcb.h> 87172043Sjfv 88171384Sjfv#include <ctype.h> 89200239Sjfv#include <err.h> 90200239Sjfv#include <fcntl.h> 91171384Sjfv#include <kvm.h> 92172043Sjfv#include <limits.h> 93172043Sjfv#include <nlist.h> 94172043Sjfv#include <paths.h> 95172043Sjfv#include <pwd.h> 96172043Sjfv#include <stdio.h> 97172043Sjfv#include <stdlib.h> 98179055Sjfv#include <string.h> 99172043Sjfv#include <unistd.h> 100190873Sjfv#include <netdb.h> 101190873Sjfv 102190873Sjfv#include "fstat.h" 103280182Sjfv 104280182Sjfv#define TEXT -1 105280182Sjfv#define CDIR -2 106280182Sjfv#define RDIR -3 107280182Sjfv#define TRACE -4 108280182Sjfv#define MMAP -5 109280182Sjfv#define JDIR -6 110320897Serj 111280182SjfvDEVS *devs; 112320897Serj 113320897Serj#ifdef notdef 114215911Sjfvstruct nlist nl[] = { 115172043Sjfv { "" }, 116172043Sjfv}; 117172043Sjfv#endif 118172043Sjfv 119292674Ssbrunoint fsflg, /* show files on same filesystem as file(s) argument */ 120172043Sjfv pflg, /* show files open by a particular pid */ 121172043Sjfv uflg; /* show files open by a particular (effective) user */ 122172043Sjfvint checkfile; /* true if restricting to particular files or filesystems */ 123172043Sjfvint nflg; /* (numerical) display f.s. and rdev as dev_t */ 124172043Sjfvint vflg; /* display errors in locating kernel data objects etc... */ 125172043Sjfvint mflg; /* include memory-mapped files */ 126172043Sjfv 127172043Sjfv 128172043Sjfvstruct file **ofiles; /* buffer of pointers to file structures */ 129172043Sjfvint maxfiles; 130172043Sjfv#define ALLOC_OFILES(d) \ 131172043Sjfv if ((d) > maxfiles) { \ 132172043Sjfv free(ofiles); \ 133172043Sjfv ofiles = malloc((d) * sizeof(struct file *)); \ 134172043Sjfv if (ofiles == NULL) { \ 135179055Sjfv err(1, NULL); \ 136172043Sjfv } \ 137251964Sjfv maxfiles = (d); \ 138251964Sjfv } 139251964Sjfv 140251964Sjfvchar *memf, *nlistf; 141251964Sjfvkvm_t *kd; 142251964Sjfv 143282289Serjstatic void fstat_kvm(int, int); 144282289Serjstatic void fstat_sysctl(int, int); 145247822Sjfvvoid dofiles(struct kinfo_proc *kp); 146247822Sjfvvoid dommap(struct kinfo_proc *kp); 147247822Sjfvvoid vtrans(struct vnode *vp, int i, int flag); 148247822Sjfvint ufs_filestat(struct vnode *vp, struct filestat *fsp); 149247822Sjfvint nfs_filestat(struct vnode *vp, struct filestat *fsp); 150247822Sjfvint devfs_filestat(struct vnode *vp, struct filestat *fsp); 151247822Sjfvchar *getmnton(struct mount *m); 152247822Sjfvvoid pipetrans(struct pipe *pi, int i, int flag); 153247822Sjfvvoid socktrans(struct socket *sock, int i); 154247822Sjfvvoid getinetproto(int number); 155247822Sjfvint getfname(const char *filename); 156247822Sjfvvoid usage(void); 157247822Sjfv 158247822Sjfv 159247822Sjfvint 160247822Sjfvmain(int argc, char **argv) 161247822Sjfv{ 162247822Sjfv struct passwd *passwd; 163247822Sjfv int arg, ch, what; 164247822Sjfv 165247822Sjfv arg = 0; 166247822Sjfv what = KERN_PROC_ALL; 167247822Sjfv nlistf = memf = NULL; 168247822Sjfv while ((ch = getopt(argc, argv, "fmnp:u:vN:M:")) != -1) 169247822Sjfv switch((char)ch) { 170247822Sjfv case 'f': 171280182Sjfv fsflg = 1; 172247822Sjfv break; 173247822Sjfv case 'M': 174247822Sjfv memf = optarg; 175247822Sjfv break; 176247822Sjfv case 'N': 177247822Sjfv nlistf = optarg; 178247822Sjfv break; 179280182Sjfv case 'm': 180247822Sjfv mflg = 1; 181247822Sjfv break; 182282289Serj case 'n': 183247822Sjfv nflg = 1; 184280182Sjfv break; 185292674Ssbruno case 'p': 186280182Sjfv if (pflg++) 187282289Serj usage(); 188280182Sjfv if (!isdigit(*optarg)) { 189280182Sjfv warnx("-p requires a process id"); 190280182Sjfv usage(); 191280182Sjfv } 192280182Sjfv what = KERN_PROC_PID; 193280182Sjfv arg = atoi(optarg); 194320897Serj break; 195280182Sjfv case 'u': 196282289Serj if (uflg++) 197280182Sjfv usage(); 198320897Serj if (!(passwd = getpwnam(optarg))) 199320897Serj errx(1, "%s: unknown uid", optarg); 200320897Serj what = KERN_PROC_UID; 201320897Serj arg = passwd->pw_uid; 202320897Serj break; 203320897Serj case 'v': 204320897Serj vflg = 1; 205320897Serj break; 206320897Serj case '?': 207320897Serj default: 208320897Serj usage(); 209320897Serj } 210320897Serj 211280182Sjfv if (*(argv += optind)) { 212247822Sjfv for (; *argv; ++argv) { 213172043Sjfv if (getfname(*argv)) 214251964Sjfv checkfile = 1; 215251964Sjfv } 216251964Sjfv if (!checkfile) /* file(s) specified, but none accessable */ 217247822Sjfv exit(1); 218171384Sjfv } 219171384Sjfv 220179055Sjfv if (fsflg && !checkfile) { 221230775Sjfv /* -f with no files means use wd */ 222172043Sjfv if (getfname(".") == 0) 223171384Sjfv exit(1); 224171384Sjfv checkfile = 1; 225171384Sjfv } 226171384Sjfv 227171384Sjfv if (memf != NULL) 228171384Sjfv fstat_kvm(what, arg); 229171384Sjfv else 230171384Sjfv fstat_sysctl(what, arg); 231171384Sjfv exit(0); 232171384Sjfv} 233179055Sjfv 234230775Sjfvstatic void 235171384Sjfvprint_header(void) 236171384Sjfv{ 237171384Sjfv 238171384Sjfv if (nflg) 239171384Sjfv printf("%s", 240171384Sjfv"USER CMD PID FD DEV INUM MODE SZ|DV R/W"); 241171384Sjfv else 242171384Sjfv printf("%s", 243171384Sjfv"USER CMD PID FD MOUNT INUM MODE SZ|DV R/W"); 244171384Sjfv if (checkfile && fsflg == 0) 245171384Sjfv printf(" NAME\n"); 246179055Sjfv else 247230775Sjfv putchar('\n'); 248171384Sjfv} 249171384Sjfv 250171384Sjfvstatic void 251179055Sjfvfstat_kvm(int what, int arg) 252171384Sjfv{ 253171384Sjfv struct kinfo_proc *p, *plast; 254171384Sjfv char buf[_POSIX2_LINE_MAX]; 255171384Sjfv int cnt; 256171384Sjfv 257171384Sjfv ALLOC_OFILES(256); /* reserve space for file pointers */ 258171384Sjfv 259171384Sjfv /* 260171384Sjfv * Discard setgid privileges if not the running kernel so that bad 261171384Sjfv * guys can't print interesting stuff from kernel memory. 262179055Sjfv */ 263230775Sjfv if (nlistf != NULL || memf != NULL) 264171384Sjfv setgid(getgid()); 265171384Sjfv 266171384Sjfv if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) 267205720Sjfv errx(1, "%s", buf); 268205720Sjfv setgid(getgid()); 269205720Sjfv#ifdef notdef 270205720Sjfv if (kvm_nlist(kd, nl) != 0) 271205720Sjfv errx(1, "no namelist: %s", kvm_geterr(kd)); 272205720Sjfv#endif 273205720Sjfv if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) 274205720Sjfv errx(1, "%s", kvm_geterr(kd)); 275205720Sjfv print_header(); 276205720Sjfv for (plast = &p[cnt]; p < plast; ++p) { 277205720Sjfv if (p->ki_stat == SZOMB) 278205720Sjfv continue; 279205720Sjfv dofiles(p); 280205720Sjfv if (mflg) 281171384Sjfv dommap(p); 282171384Sjfv } 283171384Sjfv} 284171384Sjfv 285171384Sjfvstatic void 286171384Sjfvfstat_sysctl(int what, int arg) 287171384Sjfv{ 288171384Sjfv 289179055Sjfv /* not yet implemented */ 290230775Sjfv fstat_kvm(what, arg); 291171384Sjfv} 292171384Sjfv 293171384Sjfvconst char *Uname, *Comm; 294171384Sjfvint Pid; 295171384Sjfv 296171384Sjfv#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \ 297171384Sjfv switch(i) { \ 298171384Sjfv case TEXT: \ 299171384Sjfv printf(" text"); \ 300171384Sjfv break; \ 301179055Sjfv case CDIR: \ 302230775Sjfv printf(" wd"); \ 303171384Sjfv break; \ 304171384Sjfv case RDIR: \ 305171384Sjfv printf(" root"); \ 306171384Sjfv break; \ 307171384Sjfv case TRACE: \ 308171384Sjfv printf(" tr"); \ 309171384Sjfv break; \ 310171384Sjfv case MMAP: \ 311179055Sjfv printf(" mmap"); \ 312179055Sjfv break; \ 313179055Sjfv case JDIR: \ 314171384Sjfv printf(" jail"); \ 315171384Sjfv break; \ 316171384Sjfv default: \ 317179055Sjfv printf(" %4d", i); \ 318230775Sjfv break; \ 319171384Sjfv } 320171384Sjfv 321171384Sjfv/* 322190873Sjfv * print open files attributed to this process 323190873Sjfv */ 324190873Sjfvvoid 325190873Sjfvdofiles(struct kinfo_proc *kp) 326190873Sjfv{ 327190873Sjfv int i; 328190873Sjfv struct file file; 329190873Sjfv struct filedesc filed; 330190873Sjfv 331190873Sjfv Uname = user_from_uid(kp->ki_uid, 0); 332230775Sjfv Pid = kp->ki_pid; 333190873Sjfv Comm = kp->ki_comm; 334190873Sjfv 335190873Sjfv if (kp->ki_fd == NULL) 336190873Sjfv return; 337190873Sjfv if (!KVM_READ(kp->ki_fd, &filed, sizeof (filed))) { 338190873Sjfv dprintf(stderr, "can't read filedesc at %p for pid %d\n", 339190873Sjfv (void *)kp->ki_fd, Pid); 340190873Sjfv return; 341190873Sjfv } 342190873Sjfv /* 343190873Sjfv * root directory vnode, if one 344190873Sjfv */ 345230775Sjfv if (filed.fd_rdir) 346190873Sjfv vtrans(filed.fd_rdir, RDIR, FREAD); 347190873Sjfv /* 348190873Sjfv * current working directory vnode 349190873Sjfv */ 350190873Sjfv vtrans(filed.fd_cdir, CDIR, FREAD); 351190873Sjfv /* 352190873Sjfv * jail root, if any. 353190873Sjfv */ 354190873Sjfv if (filed.fd_jdir) 355190873Sjfv vtrans(filed.fd_jdir, JDIR, FREAD); 356190873Sjfv /* 357190873Sjfv * ktrace vnode, if one 358230775Sjfv */ 359190873Sjfv if (kp->ki_tracep) 360190873Sjfv vtrans(kp->ki_tracep, TRACE, FREAD|FWRITE); 361190873Sjfv /* 362200239Sjfv * text vnode, if one 363200239Sjfv */ 364200239Sjfv if (kp->ki_textvp) 365200239Sjfv vtrans(kp->ki_textvp, TEXT, FREAD); 366200239Sjfv /* 367200239Sjfv * open files 368200239Sjfv */ 369200239Sjfv#define FPSIZE (sizeof (struct file *)) 370200239Sjfv#define MAX_LASTFILE (0x1000000) 371230775Sjfv 372200239Sjfv /* Sanity check on filed.fd_lastfile */ 373200239Sjfv if (filed.fd_lastfile <= -1 || filed.fd_lastfile > MAX_LASTFILE) 374230775Sjfv return; 375230775Sjfv 376200239Sjfv ALLOC_OFILES(filed.fd_lastfile+1); 377200239Sjfv if (!KVM_READ(filed.fd_ofiles, ofiles, 378200239Sjfv (filed.fd_lastfile+1) * FPSIZE)) { 379215911Sjfv dprintf(stderr, 380215911Sjfv "can't read file structures at %p for pid %d\n", 381215911Sjfv (void *)filed.fd_ofiles, Pid); 382215911Sjfv return; 383215911Sjfv } 384215911Sjfv for (i = 0; i <= filed.fd_lastfile; i++) { 385215911Sjfv if (ofiles[i] == NULL) 386215911Sjfv continue; 387215911Sjfv if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) { 388230775Sjfv dprintf(stderr, "can't read file %d at %p for pid %d\n", 389230775Sjfv i, (void *)ofiles[i], Pid); 390215911Sjfv continue; 391215911Sjfv } 392215911Sjfv if (file.f_type == DTYPE_VNODE) 393171384Sjfv vtrans(file.f_vnode, i, file.f_flag); 394171384Sjfv else if (file.f_type == DTYPE_SOCKET) { 395171384Sjfv if (checkfile == 0) 396171384Sjfv socktrans(file.f_data, i); 397171384Sjfv } 398171384Sjfv#ifdef DTYPE_PIPE 399171384Sjfv else if (file.f_type == DTYPE_PIPE) { 400179055Sjfv if (checkfile == 0) 401230775Sjfv pipetrans(file.f_data, i, file.f_flag); 402171384Sjfv } 403171384Sjfv#endif 404171384Sjfv#ifdef DTYPE_FIFO 405179055Sjfv else if (file.f_type == DTYPE_FIFO) { 406171384Sjfv if (checkfile == 0) 407171384Sjfv vtrans(file.f_vnode, i, file.f_flag); 408171384Sjfv } 409171384Sjfv#endif 410171384Sjfv else { 411171384Sjfv dprintf(stderr, 412179055Sjfv "unknown file type %d for file %d of pid %d\n", 413171384Sjfv file.f_type, i, Pid); 414171384Sjfv } 415171384Sjfv } 416179055Sjfv} 417171384Sjfv 418171384Sjfvvoid 419171384Sjfvdommap(struct kinfo_proc *kp) 420171384Sjfv{ 421171384Sjfv vm_map_t map; 422171384Sjfv struct vmspace vmspace; 423179055Sjfv struct vm_map_entry entry; 424171384Sjfv vm_map_entry_t entryp; 425171384Sjfv struct vm_object object; 426171384Sjfv vm_object_t objp; 427179055Sjfv int prot, fflags; 428171384Sjfv 429171384Sjfv if (!KVM_READ(kp->ki_vmspace, &vmspace, sizeof(vmspace))) { 430171384Sjfv dprintf(stderr, 431171384Sjfv "can't read vmspace at %p for pid %d\n", 432171384Sjfv (void *)kp->ki_vmspace, Pid); 433171384Sjfv return; 434171384Sjfv } 435171384Sjfv map = &vmspace.vm_map; 436171384Sjfv 437179055Sjfv for (entryp = map->header.next; 438230775Sjfv entryp != &kp->ki_vmspace->vm_map.header; entryp = entry.next) { 439171384Sjfv if (!KVM_READ(entryp, &entry, sizeof(entry))) { 440171384Sjfv dprintf(stderr, 441171384Sjfv "can't read vm_map_entry at %p for pid %d\n", 442215911Sjfv (void *)entryp, Pid); 443215911Sjfv return; 444215911Sjfv } 445215911Sjfv 446215911Sjfv if (entry.eflags & MAP_ENTRY_IS_SUB_MAP) 447215911Sjfv continue; 448215911Sjfv 449215911Sjfv if ((objp = entry.object.vm_object) == NULL) 450215911Sjfv continue; 451215911Sjfv 452215911Sjfv for (; objp; objp = object.backing_object) { 453215911Sjfv if (!KVM_READ(objp, &object, sizeof(object))) { 454215911Sjfv dprintf(stderr, 455179055Sjfv "can't read vm_object at %p for pid %d\n", 456179055Sjfv (void *)objp, Pid); 457179055Sjfv return; 458179055Sjfv } 459179055Sjfv } 460179055Sjfv 461179055Sjfv prot = entry.protection; 462179055Sjfv fflags = (prot & VM_PROT_READ ? FREAD : 0) | 463179055Sjfv (prot & VM_PROT_WRITE ? FWRITE : 0); 464179055Sjfv 465179055Sjfv switch (object.type) { 466179055Sjfv case OBJT_VNODE: 467171384Sjfv vtrans((struct vnode *)object.handle, MMAP, fflags); 468171384Sjfv break; 469171384Sjfv default: 470171384Sjfv break; 471171384Sjfv } 472171384Sjfv } 473171384Sjfv} 474171384Sjfv 475171384Sjfvvoid 476171384Sjfvvtrans(struct vnode *vp, int i, int flag) 477215911Sjfv{ 478230775Sjfv struct vnode vn; 479171384Sjfv struct filestat fst; 480171384Sjfv char rw[3], mode[15], tagstr[12], *tagptr; 481171384Sjfv const char *badtype, *filename; 482171384Sjfv 483171384Sjfv filename = badtype = NULL; 484171384Sjfv if (!KVM_READ(vp, &vn, sizeof (struct vnode))) { 485171384Sjfv dprintf(stderr, "can't read vnode at %p for pid %d\n", 486171384Sjfv (void *)vp, Pid); 487171384Sjfv return; 488171384Sjfv } 489171384Sjfv if (!KVM_READ(&vp->v_tag, &tagptr, sizeof tagptr) || 490171384Sjfv !KVM_READ(tagptr, tagstr, sizeof tagstr)) { 491171384Sjfv dprintf(stderr, "can't read v_tag at %p for pid %d\n", 492171384Sjfv (void *)vp, Pid); 493185352Sjfv return; 494185352Sjfv } 495171384Sjfv tagstr[sizeof(tagstr) - 1] = '\0'; 496171384Sjfv if (vn.v_type == VNON) 497171384Sjfv badtype = "none"; 498179055Sjfv else if (vn.v_type == VBAD) 499230775Sjfv badtype = "bad"; 500171384Sjfv else { 501171384Sjfv if (!strcmp("ufs", tagstr)) { 502171384Sjfv if (!ufs_filestat(&vn, &fst)) 503171384Sjfv badtype = "error"; 504171384Sjfv } else if (!strcmp("devfs", tagstr)) { 505179055Sjfv if (!devfs_filestat(&vn, &fst)) 506179055Sjfv badtype = "error"; 507179055Sjfv } else if (!strcmp("nfs", tagstr)) { 508179055Sjfv if (!nfs_filestat(&vn, &fst)) 509179055Sjfv badtype = "error"; 510179055Sjfv } else if (!strcmp("msdosfs", tagstr)) { 511179055Sjfv if (!msdosfs_filestat(&vn, &fst)) 512179055Sjfv badtype = "error"; 513179055Sjfv } else if (!strcmp("isofs", tagstr)) { 514230775Sjfv if (!isofs_filestat(&vn, &fst)) 515230775Sjfv badtype = "error"; 516179055Sjfv } else { 517179055Sjfv static char unknown[32]; 518179055Sjfv snprintf(unknown, sizeof unknown, "?(%s)", tagstr); 519179055Sjfv badtype = unknown; 520171384Sjfv } 521171384Sjfv } 522171384Sjfv if (checkfile) { 523171384Sjfv int fsmatch = 0; 524171384Sjfv DEVS *d; 525171384Sjfv 526171384Sjfv if (badtype) 527171384Sjfv return; 528230775Sjfv for (d = devs; d != NULL; d = d->next) 529171384Sjfv if (d->fsid == fst.fsid) { 530190873Sjfv fsmatch = 1; 531190873Sjfv if (d->ino == fst.fileid) { 532190873Sjfv filename = d->name; 533179055Sjfv break; 534230775Sjfv } 535171384Sjfv } 536171384Sjfv if (fsmatch == 0 || (filename == NULL && fsflg == 0)) 537171384Sjfv return; 538171384Sjfv } 539171384Sjfv PREFIX(i); 540171384Sjfv if (badtype) { 541171384Sjfv (void)printf(" - - %10s -\n", badtype); 542171384Sjfv return; 543171384Sjfv } 544171384Sjfv if (nflg) 545171384Sjfv (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid)); 546230775Sjfv else 547171384Sjfv (void)printf(" %-8s", getmnton(vn.v_mount)); 548190873Sjfv if (nflg) 549190873Sjfv (void)sprintf(mode, "%o", fst.mode); 550190873Sjfv else 551179055Sjfv strmode(fst.mode, mode); 552230775Sjfv (void)printf(" %6ld %10s", fst.fileid, mode); 553179055Sjfv switch (vn.v_type) { 554171384Sjfv case VBLK: 555179055Sjfv case VCHR: { 556179055Sjfv char *name; 557179055Sjfv 558179055Sjfv if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? 559179055Sjfv S_IFCHR : S_IFBLK)) == NULL)) 560179055Sjfv printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev)); 561179055Sjfv else 562179055Sjfv printf(" %6s", name); 563179055Sjfv break; 564230775Sjfv } 565179055Sjfv default: 566171384Sjfv printf(" %6lu", fst.size); 567179055Sjfv } 568280182Sjfv rw[0] = '\0'; 569280182Sjfv if (flag & FREAD) 570280182Sjfv strcat(rw, "r"); 571280182Sjfv if (flag & FWRITE) 572280182Sjfv strcat(rw, "w"); 573280182Sjfv printf(" %2s", rw); 574280182Sjfv if (filename && !fsflg) 575280182Sjfv printf(" %s", filename); 576280182Sjfv putchar('\n'); 577280182Sjfv} 578280182Sjfv 579280182Sjfvint 580280182Sjfvufs_filestat(struct vnode *vp, struct filestat *fsp) 581280182Sjfv{ 582179055Sjfv struct inode inode; 583179055Sjfv 584179055Sjfv if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) { 585179055Sjfv dprintf(stderr, "can't read inode at %p for pid %d\n", 586179055Sjfv (void *)VTOI(vp), Pid); 587179055Sjfv return 0; 588179055Sjfv } 589230775Sjfv /* 590179055Sjfv * The st_dev from stat(2) is a dev_t. These kernel structures 591179055Sjfv * contain cdev pointers. We need to convert to dev_t to make 592230775Sjfv * comparisons 593171384Sjfv */ 594171384Sjfv fsp->fsid = dev2udev(inode.i_dev); 595171384Sjfv fsp->fileid = (long)inode.i_number; 596179055Sjfv fsp->mode = (mode_t)inode.i_mode; 597179055Sjfv fsp->size = (u_long)inode.i_size; 598179055Sjfv#if should_be_but_is_hard 599179055Sjfv /* XXX - need to load i_ump and i_din[12] from kernel memory */ 600179055Sjfv if (inode.i_ump->um_fstype == UFS1) 601179055Sjfv fsp->rdev = inode.i_din1->di_rdev; 602179055Sjfv else 603230775Sjfv fsp->rdev = inode.i_din2->di_rdev; 604179055Sjfv#else 605179055Sjfv fsp->rdev = 0; 606247822Sjfv#endif 607230775Sjfv 608179055Sjfv return 1; 609179055Sjfv} 610179055Sjfv 611280182Sjfvint 612280182Sjfvdevfs_filestat(struct vnode *vp, struct filestat *fsp) 613280182Sjfv{ 614280182Sjfv struct devfs_dirent devfs_dirent; 615280182Sjfv struct mount mount; 616280182Sjfv struct vnode vnode; 617280182Sjfv 618280182Sjfv if (!KVM_READ(vp->v_data, &devfs_dirent, sizeof (devfs_dirent))) { 619280182Sjfv dprintf(stderr, "can't read devfs_dirent at %p for pid %d\n", 620280182Sjfv (void *)vp->v_data, Pid); 621280182Sjfv return 0; 622171384Sjfv } 623171384Sjfv if (!KVM_READ(vp->v_mount, &mount, sizeof (mount))) { 624171384Sjfv dprintf(stderr, "can't read mount at %p for pid %d\n", 625171384Sjfv (void *)vp->v_mount, Pid); 626171384Sjfv return 0; 627171384Sjfv } 628230775Sjfv if (!KVM_READ(devfs_dirent.de_vnode, &vnode, sizeof (vnode))) { 629171384Sjfv dprintf(stderr, "can't read vnode at %p for pid %d\n", 630179055Sjfv (void *)devfs_dirent.de_vnode, Pid); 631230775Sjfv return 0; 632230775Sjfv } 633171384Sjfv fsp->fsid = (long)mount.mnt_stat.f_fsid.val[0]; 634171384Sjfv fsp->fileid = devfs_dirent.de_inode; 635171384Sjfv fsp->mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR; 636215911Sjfv fsp->size = 0; 637215911Sjfv fsp->rdev = dev2udev(vnode.v_rdev); 638215911Sjfv 639215911Sjfv return 1; 640215911Sjfv} 641215911Sjfv 642215911Sjfvint 643215911Sjfvnfs_filestat(struct vnode *vp, struct filestat *fsp) 644215911Sjfv{ 645215911Sjfv struct nfsnode nfsnode; 646215911Sjfv mode_t mode; 647215911Sjfv 648215911Sjfv if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) { 649215911Sjfv dprintf(stderr, "can't read nfsnode at %p for pid %d\n", 650215911Sjfv (void *)VTONFS(vp), Pid); 651215911Sjfv return 0; 652215911Sjfv } 653215911Sjfv fsp->fsid = nfsnode.n_vattr.va_fsid; 654215911Sjfv fsp->fileid = nfsnode.n_vattr.va_fileid; 655215911Sjfv fsp->size = nfsnode.n_size; 656215911Sjfv fsp->rdev = nfsnode.n_vattr.va_rdev; 657215911Sjfv mode = (mode_t)nfsnode.n_vattr.va_mode; 658215911Sjfv switch (vp->v_type) { 659215911Sjfv case VREG: 660215911Sjfv mode |= S_IFREG; 661215911Sjfv break; 662215911Sjfv case VDIR: 663215911Sjfv mode |= S_IFDIR; 664215911Sjfv break; 665215911Sjfv case VBLK: 666215911Sjfv mode |= S_IFBLK; 667215911Sjfv break; 668215911Sjfv case VCHR: 669215911Sjfv mode |= S_IFCHR; 670215911Sjfv break; 671215911Sjfv case VLNK: 672215911Sjfv mode |= S_IFLNK; 673215911Sjfv break; 674200239Sjfv case VSOCK: 675171384Sjfv mode |= S_IFSOCK; 676171384Sjfv break; 677171384Sjfv case VFIFO: 678200239Sjfv mode |= S_IFIFO; 679200239Sjfv break; 680171384Sjfv case VNON: 681200239Sjfv case VBAD: 682230775Sjfv return 0; 683171384Sjfv }; 684200239Sjfv fsp->mode = mode; 685247822Sjfv 686230775Sjfv return 1; 687171384Sjfv} 688171384Sjfv 689171384Sjfv 690280182Sjfvchar * 691280182Sjfvgetmnton(struct mount *m) 692280182Sjfv{ 693280182Sjfv static struct mount mount; 694280182Sjfv static struct mtab { 695280182Sjfv struct mtab *next; 696280182Sjfv struct mount *m; 697280182Sjfv char mntonname[MNAMELEN]; 698280182Sjfv } *mhead = NULL; 699280182Sjfv struct mtab *mt; 700280182Sjfv 701280182Sjfv for (mt = mhead; mt != NULL; mt = mt->next) 702280182Sjfv if (m == mt->m) 703280182Sjfv return (mt->mntonname); 704280182Sjfv if (!KVM_READ(m, &mount, sizeof(struct mount))) { 705280182Sjfv warnx("can't read mount table at %p", (void *)m); 706179055Sjfv return (NULL); 707171384Sjfv } 708171384Sjfv if ((mt = malloc(sizeof (struct mtab))) == NULL) 709179055Sjfv err(1, NULL); 710171384Sjfv mt->m = m; 711179055Sjfv bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 712230775Sjfv mt->next = mhead; 713171384Sjfv mhead = mt; 714179055Sjfv return (mt->mntonname); 715230775Sjfv} 716171384Sjfv 717171384Sjfvvoid 718171384Sjfvpipetrans(struct pipe *pi, int i, int flag) 719179055Sjfv{ 720171384Sjfv struct pipe pip; 721171384Sjfv char rw[3]; 722171384Sjfv 723171384Sjfv PREFIX(i); 724171384Sjfv 725171384Sjfv /* fill in socket */ 726171384Sjfv if (!KVM_READ(pi, &pip, sizeof(struct pipe))) { 727179055Sjfv dprintf(stderr, "can't read pipe at %p\n", (void *)pi); 728230775Sjfv goto bad; 729171384Sjfv } 730171384Sjfv 731171384Sjfv printf("* pipe %8lx <-> %8lx", (u_long)pi, (u_long)pip.pipe_peer); 732179055Sjfv printf(" %6d", (int)pip.pipe_buffer.cnt); 733171384Sjfv rw[0] = '\0'; 734171384Sjfv if (flag & FREAD) 735171384Sjfv strcat(rw, "r"); 736171384Sjfv if (flag & FWRITE) 737171384Sjfv strcat(rw, "w"); 738171384Sjfv printf(" %2s", rw); 739171384Sjfv putchar('\n'); 740179055Sjfv return; 741230775Sjfv 742171384Sjfvbad: 743171384Sjfv printf("* error\n"); 744171384Sjfv} 745179055Sjfv 746171384Sjfvvoid 747171384Sjfvsocktrans(struct socket *sock, int i) 748171384Sjfv{ 749171384Sjfv static const char *stypename[] = { 750171384Sjfv "unused", /* 0 */ 751171384Sjfv "stream", /* 1 */ 752171384Sjfv "dgram", /* 2 */ 753179055Sjfv "raw", /* 3 */ 754230775Sjfv "rdm", /* 4 */ 755171384Sjfv "seqpak" /* 5 */ 756171384Sjfv }; 757171384Sjfv#define STYPEMAX 5 758179055Sjfv struct socket so; 759171384Sjfv struct protosw proto; 760171384Sjfv struct domain dom; 761171384Sjfv struct inpcb inpcb; 762171384Sjfv struct unpcb unpcb; 763171384Sjfv int len; 764171384Sjfv char dname[32]; 765179055Sjfv 766230775Sjfv PREFIX(i); 767171384Sjfv 768171384Sjfv /* fill in socket */ 769171384Sjfv if (!KVM_READ(sock, &so, sizeof(struct socket))) { 770179055Sjfv dprintf(stderr, "can't read sock at %p\n", (void *)sock); 771171384Sjfv goto bad; 772171384Sjfv } 773171384Sjfv 774171384Sjfv /* fill in protosw entry */ 775171384Sjfv if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) { 776171384Sjfv dprintf(stderr, "can't read protosw at %p", 777171384Sjfv (void *)so.so_proto); 778179055Sjfv goto bad; 779230775Sjfv } 780171384Sjfv 781171384Sjfv /* fill in domain */ 782171384Sjfv if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) { 783171384Sjfv dprintf(stderr, "can't read domain at %p\n", 784171384Sjfv (void *)proto.pr_domain); 785171384Sjfv goto bad; 786171384Sjfv } 787171384Sjfv 788171384Sjfv if ((len = kvm_read(kd, (u_long)dom.dom_name, dname, 789171384Sjfv sizeof(dname) - 1)) < 0) { 790171384Sjfv dprintf(stderr, "can't read domain name at %p\n", 791171384Sjfv (void *)dom.dom_name); 792171384Sjfv dname[0] = '\0'; 793171384Sjfv } 794171384Sjfv else 795179055Sjfv dname[len] = '\0'; 796230775Sjfv 797171384Sjfv if ((u_short)so.so_type > STYPEMAX) 798171384Sjfv printf("* %s ?%d", dname, so.so_type); 799171384Sjfv else 800230775Sjfv printf("* %s %s", dname, stypename[so.so_type]); 801230775Sjfv 802230775Sjfv /* 803230775Sjfv * protocol specific formatting 804230775Sjfv * 805230775Sjfv * Try to find interesting things to print. For tcp, the interesting 806230775Sjfv * thing is the address of the tcpcb, for udp and others, just the 807230775Sjfv * inpcb (socket pcb). For unix domain, its the address of the socket 808230775Sjfv * pcb and the address of the connected pcb (if connected). Otherwise 809230775Sjfv * just print the protocol number and address of the socket itself. 810230775Sjfv * The idea is not to duplicate netstat, but to make available enough 811230775Sjfv * information for further analysis. 812230775Sjfv */ 813230775Sjfv switch(dom.dom_family) { 814230775Sjfv case AF_INET: 815230775Sjfv case AF_INET6: 816230775Sjfv getinetproto(proto.pr_protocol); 817230775Sjfv if (proto.pr_protocol == IPPROTO_TCP ) { 818230775Sjfv if (so.so_pcb) { 819171384Sjfv if (kvm_read(kd, (u_long)so.so_pcb, 820171384Sjfv (char *)&inpcb, sizeof(struct inpcb)) 821171384Sjfv != sizeof(struct inpcb)) { 822171384Sjfv dprintf(stderr, 823171384Sjfv "can't read inpcb at %p\n", 824171384Sjfv (void *)so.so_pcb); 825171384Sjfv goto bad; 826171384Sjfv } 827171384Sjfv printf(" %lx", (u_long)inpcb.inp_ppcb); 828179055Sjfv } 829230775Sjfv } 830171384Sjfv else if (so.so_pcb) 831171384Sjfv printf(" %lx", (u_long)so.so_pcb); 832171384Sjfv break; 833230775Sjfv case AF_UNIX: 834230775Sjfv /* print address of pcb and connected pcb */ 835230775Sjfv if (so.so_pcb) { 836230775Sjfv printf(" %lx", (u_long)so.so_pcb); 837230775Sjfv if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb, 838230775Sjfv sizeof(struct unpcb)) != sizeof(struct unpcb)){ 839230775Sjfv dprintf(stderr, "can't read unpcb at %p\n", 840230775Sjfv (void *)so.so_pcb); 841230775Sjfv goto bad; 842230775Sjfv } 843230775Sjfv if (unpcb.unp_conn) { 844230775Sjfv char shoconn[4], *cp; 845230775Sjfv 846230775Sjfv cp = shoconn; 847230775Sjfv if (!(so.so_rcv.sb_state & SBS_CANTRCVMORE)) 848230775Sjfv *cp++ = '<'; 849230775Sjfv *cp++ = '-'; 850171384Sjfv if (!(so.so_snd.sb_state & SBS_CANTSENDMORE)) 851171384Sjfv *cp++ = '>'; 852171384Sjfv *cp = '\0'; 853171384Sjfv printf(" %s %lx", shoconn, 854171384Sjfv (u_long)unpcb.unp_conn); 855171384Sjfv } 856171384Sjfv } 857171384Sjfv break; 858179055Sjfv default: 859230775Sjfv /* print protocol number and socket address */ 860171384Sjfv printf(" %d %lx", proto.pr_protocol, (u_long)sock); 861171384Sjfv } 862171384Sjfv printf("\n"); 863171384Sjfv return; 864171384Sjfvbad: 865171384Sjfv printf("* error\n"); 866171384Sjfv} 867171384Sjfv 868179055Sjfv 869230775Sjfv/* 870171384Sjfv * Read the cdev structure in the kernel in order to work out the 871171384Sjfv * associated dev_t 872171384Sjfv */ 873190873Sjfvdev_t 874190873Sjfvdev2udev(struct cdev *dev) 875190873Sjfv{ 876190873Sjfv struct cdev si; 877190873Sjfv 878190873Sjfv if (KVM_READ(dev, &si, sizeof si)) { 879299200Spfg /* XXX: FIXME! */ 880190873Sjfv return 0; 881190873Sjfv } else { 882190873Sjfv dprintf(stderr, "can't convert cdev *%p to a dev_t\n", dev); 883190873Sjfv return -1; 884230775Sjfv } 885190873Sjfv} 886190873Sjfv 887190873Sjfv/* 888190873Sjfv * getinetproto -- 889179055Sjfv * print name of protocol number 890171384Sjfv */ 891179055Sjfvvoid 892171384Sjfvgetinetproto(int number) 893179055Sjfv{ 894171384Sjfv static int isopen; 895171384Sjfv struct protoent *pe; 896171384Sjfv 897171384Sjfv if (!isopen) 898179055Sjfv setprotoent(++isopen); 899230775Sjfv if ((pe = getprotobynumber(number)) != NULL) 900171384Sjfv printf(" %s", pe->p_name); 901179055Sjfv else 902230775Sjfv printf(" %d", number); 903171384Sjfv} 904171384Sjfv 905171384Sjfvint 906181003Sjfvgetfname(const char *filename) 907181003Sjfv{ 908181003Sjfv struct stat statbuf; 909181003Sjfv DEVS *cur; 910181003Sjfv 911181003Sjfv if (stat(filename, &statbuf)) { 912181003Sjfv warn("%s", filename); 913181003Sjfv return(0); 914181003Sjfv } 915230775Sjfv if ((cur = malloc(sizeof(DEVS))) == NULL) 916181003Sjfv err(1, NULL); 917181003Sjfv cur->next = devs; 918181003Sjfv devs = cur; 919179055Sjfv 920179055Sjfv cur->ino = statbuf.st_ino; 921179055Sjfv cur->fsid = statbuf.st_dev; 922179055Sjfv cur->name = filename; 923179055Sjfv return(1); 924179055Sjfv} 925179055Sjfv 926179055Sjfvvoid 927230775Sjfvusage(void) 928238149Sjfv{ 929179055Sjfv (void)fprintf(stderr, 930179055Sjfv "usage: fstat [-fmnv] [-M core] [-N system] [-p pid] [-u user] [file ...]\n"); 931179055Sjfv exit(1); 932238149Sjfv} 933238149Sjfv