xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/vfs.c (revision 3507:97a00d25ca9f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3507Svb160487  * Common Development and Distribution License (the "License").
6*3507Svb160487  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3507Svb160487  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
290Sstevel@tonic-gate #include <mdb/mdb_ks.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/door.h>
340Sstevel@tonic-gate #include <sys/file.h>
350Sstevel@tonic-gate #include <sys/mount.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/procfs.h>
380Sstevel@tonic-gate #include <sys/proc/prdata.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/vfs.h>
410Sstevel@tonic-gate #include <sys/vnode.h>
420Sstevel@tonic-gate #include <sys/fs/snode.h>
430Sstevel@tonic-gate #include <sys/fs/fifonode.h>
440Sstevel@tonic-gate #include <sys/fs/namenode.h>
450Sstevel@tonic-gate #include <sys/socket.h>
460Sstevel@tonic-gate #include <sys/stropts.h>
470Sstevel@tonic-gate #include <sys/socketvar.h>
480Sstevel@tonic-gate #include <sys/strsubr.h>
490Sstevel@tonic-gate #include <sys/un.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate int
520Sstevel@tonic-gate vfs_walk_init(mdb_walk_state_t *wsp)
530Sstevel@tonic-gate {
540Sstevel@tonic-gate 	if (wsp->walk_addr == NULL &&
550Sstevel@tonic-gate 	    mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
560Sstevel@tonic-gate 		mdb_warn("failed to read 'rootvfs'");
570Sstevel@tonic-gate 		return (WALK_ERR);
580Sstevel@tonic-gate 	}
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	wsp->walk_data = (void *)wsp->walk_addr;
610Sstevel@tonic-gate 	return (WALK_NEXT);
620Sstevel@tonic-gate }
630Sstevel@tonic-gate 
640Sstevel@tonic-gate int
650Sstevel@tonic-gate vfs_walk_step(mdb_walk_state_t *wsp)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate 	vfs_t vfs;
680Sstevel@tonic-gate 	int status;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) {
710Sstevel@tonic-gate 		mdb_warn("failed to read vfs_t at %p", wsp->walk_addr);
720Sstevel@tonic-gate 		return (WALK_DONE);
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	if (vfs.vfs_next == wsp->walk_data)
780Sstevel@tonic-gate 		return (WALK_DONE);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)vfs.vfs_next;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	return (status);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * Utility routine to read in a filesystem name given a vfs pointer.  If
870Sstevel@tonic-gate  * no vfssw entry for the vfs is available (as is the case with some pseudo-
880Sstevel@tonic-gate  * filesystems), we check against some known problem fs's: doorfs and
890Sstevel@tonic-gate  * portfs.  If that fails, we try to guess the filesystem name using
900Sstevel@tonic-gate  * symbol names.  fsname should be a buffer of size _ST_FSTYPSZ.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate static int
930Sstevel@tonic-gate read_fsname(uintptr_t vfsp, char *fsname)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	vfs_t vfs;
960Sstevel@tonic-gate 	struct vfssw vfssw_entry;
970Sstevel@tonic-gate 	GElf_Sym vfssw_sym, test_sym;
980Sstevel@tonic-gate 	char testname[MDB_SYM_NAMLEN];
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) {
1010Sstevel@tonic-gate 		mdb_warn("failed to read vfs %p", vfsp);
1020Sstevel@tonic-gate 		return (-1);
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) {
1060Sstevel@tonic-gate 		mdb_warn("failed to find vfssw");
1070Sstevel@tonic-gate 		return (-1);
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	/*
1110Sstevel@tonic-gate 	 * vfssw is an array; we need vfssw[vfs.vfs_fstype].
1120Sstevel@tonic-gate 	 */
1130Sstevel@tonic-gate 	if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry),
1140Sstevel@tonic-gate 	    vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype))
1150Sstevel@tonic-gate 	    == -1) {
1160Sstevel@tonic-gate 		mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype);
1170Sstevel@tonic-gate 		return (-1);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	if (vfs.vfs_fstype != 0) {
1210Sstevel@tonic-gate 		if (mdb_readstr(fsname, _ST_FSTYPSZ,
1220Sstevel@tonic-gate 		    (uintptr_t)vfssw_entry.vsw_name) == -1) {
1230Sstevel@tonic-gate 			mdb_warn("failed to find fs name %p",
1240Sstevel@tonic-gate 			    vfssw_entry.vsw_name);
1250Sstevel@tonic-gate 			return (-1);
1260Sstevel@tonic-gate 		}
1270Sstevel@tonic-gate 		return (0);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/*
1310Sstevel@tonic-gate 	 * Do precise detection for certain filesystem types that we
1320Sstevel@tonic-gate 	 * know do not appear in vfssw[], and that we depend upon in other
1330Sstevel@tonic-gate 	 * parts of the code: doorfs and portfs.
1340Sstevel@tonic-gate 	 */
1350Sstevel@tonic-gate 	if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) {
1360Sstevel@tonic-gate 		if (test_sym.st_value == vfsp) {
1370Sstevel@tonic-gate 			strcpy(fsname, "doorfs");
1380Sstevel@tonic-gate 			return (0);
1390Sstevel@tonic-gate 		}
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 	if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) {
1420Sstevel@tonic-gate 		if (test_sym.st_value == vfsp) {
1430Sstevel@tonic-gate 			strcpy(fsname, "portfs");
1440Sstevel@tonic-gate 			return (0);
1450Sstevel@tonic-gate 		}
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/*
1490Sstevel@tonic-gate 	 * Heuristic detection for other filesystems that don't have a
1500Sstevel@tonic-gate 	 * vfssw[] entry.  These tend to be named <fsname>_vfs, so we do a
1510Sstevel@tonic-gate 	 * lookup_by_addr and see if we find a symbol of that name.
1520Sstevel@tonic-gate 	 */
1530Sstevel@tonic-gate 	if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname),
1540Sstevel@tonic-gate 	    &test_sym) != -1) {
1550Sstevel@tonic-gate 		if ((strlen(testname) > 4) &&
1560Sstevel@tonic-gate 		    (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) {
1570Sstevel@tonic-gate 			testname[strlen(testname) - 4] = '\0';
1580Sstevel@tonic-gate 			strncpy(fsname, testname, _ST_FSTYPSZ);
1590Sstevel@tonic-gate 			return (0);
1600Sstevel@tonic-gate 		}
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	mdb_warn("unknown filesystem type for vfs %p", vfsp);
1640Sstevel@tonic-gate 	return (-1);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate  * Column widths for mount point display in ::fsinfo output.
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate #ifdef _LP64
1710Sstevel@tonic-gate #define	FSINFO_MNTLEN	48
1720Sstevel@tonic-gate #else
1730Sstevel@tonic-gate #define	FSINFO_MNTLEN	56
1740Sstevel@tonic-gate #endif
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate /*ARGSUSED*/
1770Sstevel@tonic-gate int
1780Sstevel@tonic-gate fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	vfs_t vfs;
1810Sstevel@tonic-gate 	int len;
1820Sstevel@tonic-gate 	int opt_v = 0;
1830Sstevel@tonic-gate 	char buf[MAXPATHLEN];
1840Sstevel@tonic-gate 	char fsname[_ST_FSTYPSZ];
1850Sstevel@tonic-gate 	mntopt_t *mntopts;
1860Sstevel@tonic-gate 	size_t size;
1870Sstevel@tonic-gate 	int i;
1880Sstevel@tonic-gate 	int first = 1;
1890Sstevel@tonic-gate 	char opt[MAX_MNTOPT_STR];
1900Sstevel@tonic-gate 	uintptr_t global_zone;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1930Sstevel@tonic-gate 		if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) {
1940Sstevel@tonic-gate 			mdb_warn("failed to walk file system list");
1950Sstevel@tonic-gate 			return (DCMD_ERR);
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 		return (DCMD_OK);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
2010Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
2020Sstevel@tonic-gate 		return (DCMD_USAGE);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
2050Sstevel@tonic-gate 		mdb_printf("%<u>%?s %-15s %s%</u>\n",
2060Sstevel@tonic-gate 		    "VFSP", "FS", "MOUNT");
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) {
2090Sstevel@tonic-gate 		mdb_warn("failed to read vfs_t %p", addr);
2100Sstevel@tonic-gate 		return (DCMD_ERR);
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf,
2140Sstevel@tonic-gate 	    sizeof (buf))) <= 0)
2150Sstevel@tonic-gate 		strcpy(buf, "??");
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	else if (!opt_v && (len >= FSINFO_MNTLEN))
2180Sstevel@tonic-gate 		/*
2190Sstevel@tonic-gate 		 * In normal mode, we truncate the path to keep the output
2200Sstevel@tonic-gate 		 * clean.  In -v mode, we just print the full path.
2210Sstevel@tonic-gate 		 */
2220Sstevel@tonic-gate 		strcpy(&buf[FSINFO_MNTLEN - 4], "...");
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	if (read_fsname(addr, fsname) == -1)
2250Sstevel@tonic-gate 		return (DCMD_ERR);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	mdb_printf("%0?p %-15s %s\n", addr, fsname, buf);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	if (!opt_v)
2300Sstevel@tonic-gate 		return (DCMD_OK);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	/*
2330Sstevel@tonic-gate 	 * Print 'resource' string; this shows what we're mounted upon.
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 	if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf,
2360Sstevel@tonic-gate 	    MAXPATHLEN) <= 0)
2370Sstevel@tonic-gate 		strcpy(buf, "??");
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	mdb_printf("%?s %s\n", "R:", buf);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/*
2420Sstevel@tonic-gate 	 * Print mount options array; it sucks to be a mimic, but we copy
2430Sstevel@tonic-gate 	 * the same logic as in mntvnops.c for adding zone= tags, and we
2440Sstevel@tonic-gate 	 * don't bother with the obsolete dev= option.
2450Sstevel@tonic-gate 	 */
2460Sstevel@tonic-gate 	size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t);
2470Sstevel@tonic-gate 	mntopts = mdb_alloc(size, UM_SLEEP | UM_GC);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (mdb_vread(mntopts, size,
2500Sstevel@tonic-gate 	    (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) {
2510Sstevel@tonic-gate 		mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list);
2520Sstevel@tonic-gate 		return (DCMD_ERR);
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) {
2560Sstevel@tonic-gate 		if (mntopts[i].mo_flags & MO_SET) {
2570Sstevel@tonic-gate 			if (mdb_readstr(opt, sizeof (opt),
2580Sstevel@tonic-gate 			    (uintptr_t)mntopts[i].mo_name) == -1) {
2590Sstevel@tonic-gate 				mdb_warn("failed to read mntopt name %p",
2600Sstevel@tonic-gate 				    mntopts[i].mo_name);
2610Sstevel@tonic-gate 				return (DCMD_ERR);
2620Sstevel@tonic-gate 			}
2630Sstevel@tonic-gate 			if (first) {
2640Sstevel@tonic-gate 				mdb_printf("%?s ", "O:");
2650Sstevel@tonic-gate 				first = 0;
2660Sstevel@tonic-gate 			} else {
2670Sstevel@tonic-gate 				mdb_printf(",");
2680Sstevel@tonic-gate 			}
2690Sstevel@tonic-gate 			mdb_printf("%s", opt);
2700Sstevel@tonic-gate 			if (mntopts[i].mo_flags & MO_HASVALUE) {
2710Sstevel@tonic-gate 				if (mdb_readstr(opt, sizeof (opt),
2720Sstevel@tonic-gate 				    (uintptr_t)mntopts[i].mo_arg) == -1) {
2730Sstevel@tonic-gate 					mdb_warn("failed to read mntopt "
2740Sstevel@tonic-gate 					    "value %p", mntopts[i].mo_arg);
2750Sstevel@tonic-gate 					return (DCMD_ERR);
2760Sstevel@tonic-gate 				}
2770Sstevel@tonic-gate 				mdb_printf("=%s", opt);
2780Sstevel@tonic-gate 			}
2790Sstevel@tonic-gate 		}
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (mdb_readvar(&global_zone, "global_zone") == -1) {
2830Sstevel@tonic-gate 		mdb_warn("failed to locate global_zone");
2840Sstevel@tonic-gate 		return (DCMD_ERR);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	if ((vfs.vfs_zone != NULL) &&
2880Sstevel@tonic-gate 	    ((uintptr_t)vfs.vfs_zone != global_zone)) {
2890Sstevel@tonic-gate 		zone_t z;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) {
2920Sstevel@tonic-gate 			mdb_warn("failed to read zone");
2930Sstevel@tonic-gate 			return (DCMD_ERR);
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 		/*
2960Sstevel@tonic-gate 		 * zone names are much shorter than MAX_MNTOPT_STR
2970Sstevel@tonic-gate 		 */
2980Sstevel@tonic-gate 		if (mdb_readstr(opt, sizeof (opt),
2990Sstevel@tonic-gate 		    (uintptr_t)z.zone_name) == -1) {
3000Sstevel@tonic-gate 			mdb_warn("failed to read zone name");
3010Sstevel@tonic-gate 			return (DCMD_ERR);
3020Sstevel@tonic-gate 		}
3030Sstevel@tonic-gate 		if (first) {
3040Sstevel@tonic-gate 			mdb_printf("%?s ", "O:");
3050Sstevel@tonic-gate 		} else {
3060Sstevel@tonic-gate 			mdb_printf(",");
3070Sstevel@tonic-gate 		}
3080Sstevel@tonic-gate 		mdb_printf("zone=%s", opt);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 	return (DCMD_OK);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate #define	REALVP_DONE	0
3150Sstevel@tonic-gate #define	REALVP_ERR	1
3160Sstevel@tonic-gate #define	REALVP_CONTINUE	2
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate static int
3190Sstevel@tonic-gate next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	char fsname[_ST_FSTYPSZ];
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	*outvp = invp;
3240Sstevel@tonic-gate 	if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) {
3250Sstevel@tonic-gate 		mdb_warn("failed to read vnode at %p", invp);
3260Sstevel@tonic-gate 		return (REALVP_ERR);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1)
3300Sstevel@tonic-gate 		return (REALVP_ERR);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	/*
3330Sstevel@tonic-gate 	 * We know how to do 'realvp' for as many filesystems as possible;
3340Sstevel@tonic-gate 	 * for all other filesystems, we assume that the vp we are given
3350Sstevel@tonic-gate 	 * is the realvp.  In the kernel, a realvp operation will sometimes
3360Sstevel@tonic-gate 	 * dig through multiple layers.  Here, we only fetch the pointer
3370Sstevel@tonic-gate 	 * to the next layer down.  This allows dcmds to print out the
3380Sstevel@tonic-gate 	 * various layers.
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 	if (strcmp(fsname, "fifofs") == 0) {
3410Sstevel@tonic-gate 		fifonode_t fn;
3420Sstevel@tonic-gate 		if (mdb_vread(&fn, sizeof (fn),
3430Sstevel@tonic-gate 		    (uintptr_t)outvn->v_data) == -1) {
3440Sstevel@tonic-gate 			mdb_warn("failed to read fifonode");
3450Sstevel@tonic-gate 			return (REALVP_ERR);
3460Sstevel@tonic-gate 		}
3470Sstevel@tonic-gate 		*outvp = (uintptr_t)fn.fn_realvp;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	} else if (strcmp(fsname, "namefs") == 0) {
3500Sstevel@tonic-gate 		struct namenode nn;
3510Sstevel@tonic-gate 		if (mdb_vread(&nn, sizeof (nn),
3520Sstevel@tonic-gate 		    (uintptr_t)outvn->v_data) == -1) {
3530Sstevel@tonic-gate 			mdb_warn("failed to read namenode");
3540Sstevel@tonic-gate 			return (REALVP_ERR);
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 		*outvp = (uintptr_t)nn.nm_filevp;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	} else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) {
3590Sstevel@tonic-gate 		struct stdata stream;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		/*
3620Sstevel@tonic-gate 		 * Sockets have a strange and different layering scheme; we
3630Sstevel@tonic-gate 		 * hop over into the sockfs vnode (accessible via the stream
3640Sstevel@tonic-gate 		 * head) if possible.
3650Sstevel@tonic-gate 		 */
3660Sstevel@tonic-gate 		if (mdb_vread(&stream, sizeof (stream),
3670Sstevel@tonic-gate 		    (uintptr_t)outvn->v_stream) == -1) {
3680Sstevel@tonic-gate 			mdb_warn("failed to read stream data");
3690Sstevel@tonic-gate 			return (REALVP_ERR);
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 		*outvp = (uintptr_t)stream.sd_vnode;
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	if (*outvp == invp || *outvp == NULL)
3750Sstevel@tonic-gate 		return (REALVP_DONE);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	return (REALVP_CONTINUE);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate static void
3810Sstevel@tonic-gate pfiles_print_addr(struct sockaddr *addr)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	struct sockaddr_in *s_in;
3840Sstevel@tonic-gate 	struct sockaddr_un *s_un;
3850Sstevel@tonic-gate 	struct sockaddr_in6 *s_in6;
386*3507Svb160487 	in_port_t port;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	switch (addr->sa_family) {
3890Sstevel@tonic-gate 	case AF_INET:
3900Sstevel@tonic-gate 		/*LINTED: alignment*/
3910Sstevel@tonic-gate 		s_in = (struct sockaddr_in *)addr;
392*3507Svb160487 		mdb_nhconvert(&port, &s_in->sin_port, sizeof (port));
393*3507Svb160487 		mdb_printf("AF_INET %I %d ", s_in->sin_addr.s_addr, port);
3940Sstevel@tonic-gate 		break;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	case AF_INET6:
3970Sstevel@tonic-gate 		/*LINTED: alignment*/
3980Sstevel@tonic-gate 		s_in6 = (struct sockaddr_in6 *)addr;
399*3507Svb160487 		mdb_nhconvert(&port, &s_in6->sin6_port, sizeof (port));
400*3507Svb160487 		mdb_printf("AF_INET6 %N %d ", &(s_in6->sin6_addr), port);
4010Sstevel@tonic-gate 		break;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	case AF_UNIX:
4040Sstevel@tonic-gate 		s_un = (struct sockaddr_un *)addr;
4050Sstevel@tonic-gate 		mdb_printf("AF_UNIX %s ", s_un->sun_path);
4060Sstevel@tonic-gate 		break;
4070Sstevel@tonic-gate 	default:
4080Sstevel@tonic-gate 		mdb_printf("AF_?? (%d) ", addr->sa_family);
4090Sstevel@tonic-gate 		break;
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate static int
4150Sstevel@tonic-gate pfiles_get_sonode(uintptr_t vp, struct sonode *sonode)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	vnode_t v;
4180Sstevel@tonic-gate 	struct stdata stream;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), vp) == -1) {
4210Sstevel@tonic-gate 		mdb_warn("failed to read socket vnode");
4220Sstevel@tonic-gate 		return (-1);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	if (mdb_vread(&stream, sizeof (stream), (uintptr_t)v.v_stream) == -1) {
4260Sstevel@tonic-gate 		mdb_warn("failed to read stream data");
4270Sstevel@tonic-gate 		return (-1);
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), (uintptr_t)stream.sd_vnode) == -1) {
4310Sstevel@tonic-gate 		mdb_warn("failed to read stream vnode");
4320Sstevel@tonic-gate 		return (-1);
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (mdb_vread(sonode, sizeof (struct sonode),
4360Sstevel@tonic-gate 	    (uintptr_t)v.v_data) == -1) {
4370Sstevel@tonic-gate 		mdb_warn("failed to read sonode");
4380Sstevel@tonic-gate 		return (-1);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	return (0);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate /*
4450Sstevel@tonic-gate  * Do some digging to get a reasonable pathname for this vnode. 'path'
4460Sstevel@tonic-gate  * should point at a buffer of MAXPATHLEN in size.
4470Sstevel@tonic-gate  */
4480Sstevel@tonic-gate static int
4490Sstevel@tonic-gate pfiles_dig_pathname(uintptr_t vp, char *path)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	vnode_t v;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	bzero(path, MAXPATHLEN);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), vp) == -1) {
4560Sstevel@tonic-gate 		mdb_warn("failed to read vnode");
4570Sstevel@tonic-gate 		return (-1);
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (v.v_path == NULL) {
4610Sstevel@tonic-gate 		/*
4620Sstevel@tonic-gate 		 * fifo's and doors are special.   Some have pathnames, and
4630Sstevel@tonic-gate 		 * some do not.  And for these, it is pointless to go off to
4640Sstevel@tonic-gate 		 * mdb_vnode2path, which is very slow.
4650Sstevel@tonic-gate 		 *
4660Sstevel@tonic-gate 		 * Event ports never have a pathname.
4670Sstevel@tonic-gate 		 */
4680Sstevel@tonic-gate 		if (v.v_type == VFIFO || v.v_type == VDOOR || v.v_type == VPORT)
4690Sstevel@tonic-gate 			return (0);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 		/*
4720Sstevel@tonic-gate 		 * For sockets, we won't find a path unless we print the path
4730Sstevel@tonic-gate 		 * associated with the accessvp.
4740Sstevel@tonic-gate 		 */
4750Sstevel@tonic-gate 		if (v.v_type == VSOCK) {
4760Sstevel@tonic-gate 			struct sonode sonode;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 			if (pfiles_get_sonode(vp, &sonode) == -1) {
4790Sstevel@tonic-gate 				return (-1);
4800Sstevel@tonic-gate 			}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 			vp = (uintptr_t)sonode.so_accessvp;
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/*
4880Sstevel@tonic-gate 	 * mdb_vnode2path will print an error for us as needed, but not
4890Sstevel@tonic-gate 	 * finding a pathname is not really an error, so we plow on.
4900Sstevel@tonic-gate 	 */
4910Sstevel@tonic-gate 	(void) mdb_vnode2path(vp, path, MAXPATHLEN);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	/*
4940Sstevel@tonic-gate 	 * A common problem is that device pathnames are prefixed with
4950Sstevel@tonic-gate 	 * /dev/../devices/.  We just clean those up slightly:
4960Sstevel@tonic-gate 	 * 	/dev/../devices/<mumble> --> /devices/<mumble>
4970Sstevel@tonic-gate 	 * 	/dev/pts/../../devices/<mumble> --> /devices/<mumble>
4980Sstevel@tonic-gate 	 */
4990Sstevel@tonic-gate 	if (strncmp("/dev/../devices/", path, strlen("/dev/../devices/")) == 0)
5000Sstevel@tonic-gate 		strcpy(path, path + 7);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if (strncmp("/dev/pts/../../devices/", path,
5030Sstevel@tonic-gate 	    strlen("/dev/pts/../../devices/")) == 0)
5040Sstevel@tonic-gate 		strcpy(path, path + 14);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	return (0);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate const struct fs_type {
5100Sstevel@tonic-gate 	int type;
5110Sstevel@tonic-gate 	const char *name;
5120Sstevel@tonic-gate } fs_types[] = {
5130Sstevel@tonic-gate 	{ VNON,   "NON" },
5140Sstevel@tonic-gate 	{ VREG,   "REG" },
5150Sstevel@tonic-gate 	{ VDIR,   "DIR" },
5160Sstevel@tonic-gate 	{ VBLK,   "BLK" },
5170Sstevel@tonic-gate 	{ VCHR,   "CHR" },
5180Sstevel@tonic-gate 	{ VLNK,   "LNK" },
5190Sstevel@tonic-gate 	{ VFIFO,  "FIFO" },
5200Sstevel@tonic-gate 	{ VDOOR,  "DOOR" },
5210Sstevel@tonic-gate 	{ VPROC,  "PROC" },
5220Sstevel@tonic-gate 	{ VSOCK,  "SOCK" },
5230Sstevel@tonic-gate 	{ VPORT,  "PORT" },
5240Sstevel@tonic-gate 	{ VBAD,   "BAD" }
5250Sstevel@tonic-gate };
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate #define	NUM_FS_TYPES (sizeof (fs_types) / sizeof (struct fs_type))
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate struct pfiles_cbdata {
5300Sstevel@tonic-gate 	int opt_p;
5310Sstevel@tonic-gate 	int fd;
5320Sstevel@tonic-gate };
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate static int
5350Sstevel@tonic-gate pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate 	vnode_t v, layer_vn;
5380Sstevel@tonic-gate 	int myfd = cb->fd;
5390Sstevel@tonic-gate 	const char *type;
5400Sstevel@tonic-gate 	char path[MAXPATHLEN];
5410Sstevel@tonic-gate 	uintptr_t top_vnodep, realvpp;
5420Sstevel@tonic-gate 	char fsname[_ST_FSTYPSZ];
5430Sstevel@tonic-gate 	int err, i;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	cb->fd++;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (addr == NULL) {
5480Sstevel@tonic-gate 		return (WALK_NEXT);
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	top_vnodep = realvpp = (uintptr_t)f->f_vnode;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), realvpp) == -1) {
5540Sstevel@tonic-gate 		mdb_warn("failed to read vnode");
5550Sstevel@tonic-gate 		return (DCMD_ERR);
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	type = "?";
5590Sstevel@tonic-gate 	for (i = 0; i <= NUM_FS_TYPES; i++) {
5600Sstevel@tonic-gate 		if (fs_types[i].type == v.v_type)
5610Sstevel@tonic-gate 			type = fs_types[i].name;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	do {
5650Sstevel@tonic-gate 		uintptr_t next_realvpp;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		err = next_realvp(realvpp, &layer_vn, &next_realvpp);
5680Sstevel@tonic-gate 		if (next_realvpp != NULL)
5690Sstevel@tonic-gate 			realvpp = next_realvpp;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	} while (err == REALVP_CONTINUE);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if (err == REALVP_ERR) {
5740Sstevel@tonic-gate 		mdb_warn("failed to do realvp() for %p", realvpp);
5750Sstevel@tonic-gate 		return (DCMD_ERR);
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1)
5790Sstevel@tonic-gate 		return (DCMD_ERR);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	if (cb->opt_p) {
5840Sstevel@tonic-gate 		if (pfiles_dig_pathname(top_vnodep, path) == -1)
5850Sstevel@tonic-gate 			return (DCMD_ERR);
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 		mdb_printf("%s\n", path);
5880Sstevel@tonic-gate 		return (DCMD_OK);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/*
5920Sstevel@tonic-gate 	 * Sockets generally don't have interesting pathnames; we only
5930Sstevel@tonic-gate 	 * show those in the '-p' view.
5940Sstevel@tonic-gate 	 */
5950Sstevel@tonic-gate 	path[0] = '\0';
5960Sstevel@tonic-gate 	if (v.v_type != VSOCK) {
5970Sstevel@tonic-gate 		if (pfiles_dig_pathname(top_vnodep, path) == -1)
5980Sstevel@tonic-gate 			return (DCMD_ERR);
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate 	mdb_printf("%s%s", path, path[0] == '\0' ? "" : " ");
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	switch (v.v_type) {
6030Sstevel@tonic-gate 	case VDOOR:
6040Sstevel@tonic-gate 	{
6050Sstevel@tonic-gate 		door_node_t doornode;
6060Sstevel@tonic-gate 		proc_t pr;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		if (mdb_vread(&doornode, sizeof (doornode),
6090Sstevel@tonic-gate 		    (uintptr_t)layer_vn.v_data) == -1) {
6100Sstevel@tonic-gate 			mdb_warn("failed to read door_node");
6110Sstevel@tonic-gate 			return (DCMD_ERR);
6120Sstevel@tonic-gate 		}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 		if (mdb_vread(&pr, sizeof (pr),
6150Sstevel@tonic-gate 		    (uintptr_t)doornode.door_target) == -1) {
6160Sstevel@tonic-gate 			mdb_warn("failed to read door server process %p",
6170Sstevel@tonic-gate 			    doornode.door_target);
6180Sstevel@tonic-gate 			return (DCMD_ERR);
6190Sstevel@tonic-gate 		}
6200Sstevel@tonic-gate 		mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm,
6210Sstevel@tonic-gate 		    doornode.door_target);
6220Sstevel@tonic-gate 		break;
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	case VSOCK:
6260Sstevel@tonic-gate 	{
6270Sstevel@tonic-gate 		struct sonode sonode;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		if (pfiles_get_sonode(realvpp, &sonode) == -1)
6300Sstevel@tonic-gate 			return (DCMD_ERR);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 		/*
6330Sstevel@tonic-gate 		 * If the address is cached in the sonode, use it; otherwise,
6340Sstevel@tonic-gate 		 * we print nothing.
6350Sstevel@tonic-gate 		 */
6360Sstevel@tonic-gate 		if (sonode.so_state & SS_LADDR_VALID) {
6370Sstevel@tonic-gate 			struct sockaddr *laddr =
6380Sstevel@tonic-gate 			    mdb_alloc(sonode.so_laddr_len, UM_SLEEP);
6390Sstevel@tonic-gate 			if (mdb_vread(laddr, sonode.so_laddr_len,
6400Sstevel@tonic-gate 			    (uintptr_t)sonode.so_laddr_sa) == -1) {
6410Sstevel@tonic-gate 				mdb_warn("failed to read sonode socket addr");
6420Sstevel@tonic-gate 				return (DCMD_ERR);
6430Sstevel@tonic-gate 			}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 			mdb_printf("socket: ");
6460Sstevel@tonic-gate 			pfiles_print_addr(laddr);
6470Sstevel@tonic-gate 		}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 		if (sonode.so_state & SS_FADDR_VALID) {
6500Sstevel@tonic-gate 			struct sockaddr *faddr =
6510Sstevel@tonic-gate 			    mdb_alloc(sonode.so_faddr_len, UM_SLEEP);
6520Sstevel@tonic-gate 			if (mdb_vread(faddr, sonode.so_faddr_len,
6530Sstevel@tonic-gate 			    (uintptr_t)sonode.so_faddr_sa) == -1) {
6540Sstevel@tonic-gate 				mdb_warn("failed to read sonode remote addr");
6550Sstevel@tonic-gate 				return (DCMD_ERR);
6560Sstevel@tonic-gate 			}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 			mdb_printf("remote: ");
6590Sstevel@tonic-gate 			pfiles_print_addr(faddr);
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 		break;
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	case VPORT:
6650Sstevel@tonic-gate 		mdb_printf("[event port (port=%p)]", v.v_data);
6660Sstevel@tonic-gate 		break;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	case VPROC:
6690Sstevel@tonic-gate 	{
6700Sstevel@tonic-gate 		prnode_t prnode;
6710Sstevel@tonic-gate 		prcommon_t prcommon;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 		if (mdb_vread(&prnode, sizeof (prnode),
6740Sstevel@tonic-gate 		    (uintptr_t)layer_vn.v_data) == -1) {
6750Sstevel@tonic-gate 			mdb_warn("failed to read prnode");
6760Sstevel@tonic-gate 			return (DCMD_ERR);
6770Sstevel@tonic-gate 		}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 		if (mdb_vread(&prcommon, sizeof (prcommon),
6800Sstevel@tonic-gate 		    (uintptr_t)prnode.pr_common) == -1) {
6810Sstevel@tonic-gate 			mdb_warn("failed to read prcommon %p",
6820Sstevel@tonic-gate 			    prnode.pr_common);
6830Sstevel@tonic-gate 			return (DCMD_ERR);
6840Sstevel@tonic-gate 		}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 		mdb_printf("(proc=%p)", prcommon.prc_proc);
6870Sstevel@tonic-gate 		break;
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	default:
6910Sstevel@tonic-gate 		break;
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	mdb_printf("\n");
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	return (WALK_NEXT);
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate static int
7010Sstevel@tonic-gate file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	int myfd = cb->fd;
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	cb->fd++;
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if (addr == NULL) {
7080Sstevel@tonic-gate 		return (WALK_NEXT);
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/*
7120Sstevel@tonic-gate 	 * We really need 20 digits to print a 64-bit offset_t, but this
7130Sstevel@tonic-gate 	 * is exceedingly rare, so we cheat and assume a column width of 10
7140Sstevel@tonic-gate 	 * digits, in order to fit everything cleanly into 80 columns.
7150Sstevel@tonic-gate 	 */
7160Sstevel@tonic-gate 	mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n",
7170Sstevel@tonic-gate 	    addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred,
7180Sstevel@tonic-gate 	    f->f_count);
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	return (WALK_NEXT);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate int
7240Sstevel@tonic-gate pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7250Sstevel@tonic-gate {
7260Sstevel@tonic-gate 	int opt_f = 0;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	struct pfiles_cbdata cb;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	bzero(&cb, sizeof (cb));
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
7330Sstevel@tonic-gate 		return (DCMD_USAGE);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
7360Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p,
7370Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc)
7380Sstevel@tonic-gate 		return (DCMD_USAGE);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (opt_f) {
7410Sstevel@tonic-gate 		mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE",
7420Sstevel@tonic-gate 		    "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT");
7430Sstevel@tonic-gate 		if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb,
7440Sstevel@tonic-gate 		    addr) == -1) {
7450Sstevel@tonic-gate 			mdb_warn("failed to walk 'allfile'");
7460Sstevel@tonic-gate 			return (DCMD_ERR);
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 	} else {
7490Sstevel@tonic-gate 		mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE");
7500Sstevel@tonic-gate 		if (cb.opt_p)
7510Sstevel@tonic-gate 			mdb_printf("PATH");
7520Sstevel@tonic-gate 		else
7530Sstevel@tonic-gate 			mdb_printf("INFO");
7540Sstevel@tonic-gate 		mdb_printf("%</u>\n");
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb,
7570Sstevel@tonic-gate 		    addr) == -1) {
7580Sstevel@tonic-gate 			mdb_warn("failed to walk 'allfile'");
7590Sstevel@tonic-gate 			return (DCMD_ERR);
7600Sstevel@tonic-gate 		}
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	return (DCMD_OK);
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate void
7680Sstevel@tonic-gate pfiles_help(void)
7690Sstevel@tonic-gate {
7700Sstevel@tonic-gate 	mdb_printf(
7710Sstevel@tonic-gate 	    "Given the address of a process, print information about files\n"
7720Sstevel@tonic-gate 	    "which the process has open.  By default, this includes decoded\n"
7730Sstevel@tonic-gate 	    "information about the file depending on file and filesystem type\n"
7740Sstevel@tonic-gate 	    "\n"
7750Sstevel@tonic-gate 	    "\t-p\tPathnames; omit decoded information.  Only display "
7760Sstevel@tonic-gate 	    "pathnames\n"
7770Sstevel@tonic-gate 	    "\t-f\tfile_t view; show the file_t structure corresponding to "
7780Sstevel@tonic-gate 	    "the fd\n");
7790Sstevel@tonic-gate }
780