xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/vfs.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
30*0Sstevel@tonic-gate #include <mdb/mdb_ks.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/systm.h>
34*0Sstevel@tonic-gate #include <sys/door.h>
35*0Sstevel@tonic-gate #include <sys/file.h>
36*0Sstevel@tonic-gate #include <sys/mount.h>
37*0Sstevel@tonic-gate #include <sys/proc.h>
38*0Sstevel@tonic-gate #include <sys/procfs.h>
39*0Sstevel@tonic-gate #include <sys/proc/prdata.h>
40*0Sstevel@tonic-gate #include <sys/stat.h>
41*0Sstevel@tonic-gate #include <sys/vfs.h>
42*0Sstevel@tonic-gate #include <sys/vnode.h>
43*0Sstevel@tonic-gate #include <sys/fs/snode.h>
44*0Sstevel@tonic-gate #include <sys/fs/fifonode.h>
45*0Sstevel@tonic-gate #include <sys/fs/namenode.h>
46*0Sstevel@tonic-gate #include <sys/socket.h>
47*0Sstevel@tonic-gate #include <sys/stropts.h>
48*0Sstevel@tonic-gate #include <sys/socketvar.h>
49*0Sstevel@tonic-gate #include <sys/strsubr.h>
50*0Sstevel@tonic-gate #include <sys/un.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate int
53*0Sstevel@tonic-gate vfs_walk_init(mdb_walk_state_t *wsp)
54*0Sstevel@tonic-gate {
55*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL &&
56*0Sstevel@tonic-gate 	    mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
57*0Sstevel@tonic-gate 		mdb_warn("failed to read 'rootvfs'");
58*0Sstevel@tonic-gate 		return (WALK_ERR);
59*0Sstevel@tonic-gate 	}
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	wsp->walk_data = (void *)wsp->walk_addr;
62*0Sstevel@tonic-gate 	return (WALK_NEXT);
63*0Sstevel@tonic-gate }
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate int
66*0Sstevel@tonic-gate vfs_walk_step(mdb_walk_state_t *wsp)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	vfs_t vfs;
69*0Sstevel@tonic-gate 	int status;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) {
72*0Sstevel@tonic-gate 		mdb_warn("failed to read vfs_t at %p", wsp->walk_addr);
73*0Sstevel@tonic-gate 		return (WALK_DONE);
74*0Sstevel@tonic-gate 	}
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	if (vfs.vfs_next == wsp->walk_data)
79*0Sstevel@tonic-gate 		return (WALK_DONE);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)vfs.vfs_next;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	return (status);
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate /*
87*0Sstevel@tonic-gate  * Utility routine to read in a filesystem name given a vfs pointer.  If
88*0Sstevel@tonic-gate  * no vfssw entry for the vfs is available (as is the case with some pseudo-
89*0Sstevel@tonic-gate  * filesystems), we check against some known problem fs's: doorfs and
90*0Sstevel@tonic-gate  * portfs.  If that fails, we try to guess the filesystem name using
91*0Sstevel@tonic-gate  * symbol names.  fsname should be a buffer of size _ST_FSTYPSZ.
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate static int
94*0Sstevel@tonic-gate read_fsname(uintptr_t vfsp, char *fsname)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	vfs_t vfs;
97*0Sstevel@tonic-gate 	struct vfssw vfssw_entry;
98*0Sstevel@tonic-gate 	GElf_Sym vfssw_sym, test_sym;
99*0Sstevel@tonic-gate 	char testname[MDB_SYM_NAMLEN];
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) {
102*0Sstevel@tonic-gate 		mdb_warn("failed to read vfs %p", vfsp);
103*0Sstevel@tonic-gate 		return (-1);
104*0Sstevel@tonic-gate 	}
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) {
107*0Sstevel@tonic-gate 		mdb_warn("failed to find vfssw");
108*0Sstevel@tonic-gate 		return (-1);
109*0Sstevel@tonic-gate 	}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	/*
112*0Sstevel@tonic-gate 	 * vfssw is an array; we need vfssw[vfs.vfs_fstype].
113*0Sstevel@tonic-gate 	 */
114*0Sstevel@tonic-gate 	if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry),
115*0Sstevel@tonic-gate 	    vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype))
116*0Sstevel@tonic-gate 	    == -1) {
117*0Sstevel@tonic-gate 		mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype);
118*0Sstevel@tonic-gate 		return (-1);
119*0Sstevel@tonic-gate 	}
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	if (vfs.vfs_fstype != 0) {
122*0Sstevel@tonic-gate 		if (mdb_readstr(fsname, _ST_FSTYPSZ,
123*0Sstevel@tonic-gate 		    (uintptr_t)vfssw_entry.vsw_name) == -1) {
124*0Sstevel@tonic-gate 			mdb_warn("failed to find fs name %p",
125*0Sstevel@tonic-gate 			    vfssw_entry.vsw_name);
126*0Sstevel@tonic-gate 			return (-1);
127*0Sstevel@tonic-gate 		}
128*0Sstevel@tonic-gate 		return (0);
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	/*
132*0Sstevel@tonic-gate 	 * Do precise detection for certain filesystem types that we
133*0Sstevel@tonic-gate 	 * know do not appear in vfssw[], and that we depend upon in other
134*0Sstevel@tonic-gate 	 * parts of the code: doorfs and portfs.
135*0Sstevel@tonic-gate 	 */
136*0Sstevel@tonic-gate 	if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) {
137*0Sstevel@tonic-gate 		if (test_sym.st_value == vfsp) {
138*0Sstevel@tonic-gate 			strcpy(fsname, "doorfs");
139*0Sstevel@tonic-gate 			return (0);
140*0Sstevel@tonic-gate 		}
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 	if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) {
143*0Sstevel@tonic-gate 		if (test_sym.st_value == vfsp) {
144*0Sstevel@tonic-gate 			strcpy(fsname, "portfs");
145*0Sstevel@tonic-gate 			return (0);
146*0Sstevel@tonic-gate 		}
147*0Sstevel@tonic-gate 	}
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	/*
150*0Sstevel@tonic-gate 	 * Heuristic detection for other filesystems that don't have a
151*0Sstevel@tonic-gate 	 * vfssw[] entry.  These tend to be named <fsname>_vfs, so we do a
152*0Sstevel@tonic-gate 	 * lookup_by_addr and see if we find a symbol of that name.
153*0Sstevel@tonic-gate 	 */
154*0Sstevel@tonic-gate 	if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname),
155*0Sstevel@tonic-gate 	    &test_sym) != -1) {
156*0Sstevel@tonic-gate 		if ((strlen(testname) > 4) &&
157*0Sstevel@tonic-gate 		    (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) {
158*0Sstevel@tonic-gate 			testname[strlen(testname) - 4] = '\0';
159*0Sstevel@tonic-gate 			strncpy(fsname, testname, _ST_FSTYPSZ);
160*0Sstevel@tonic-gate 			return (0);
161*0Sstevel@tonic-gate 		}
162*0Sstevel@tonic-gate 	}
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	mdb_warn("unknown filesystem type for vfs %p", vfsp);
165*0Sstevel@tonic-gate 	return (-1);
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /*
169*0Sstevel@tonic-gate  * Column widths for mount point display in ::fsinfo output.
170*0Sstevel@tonic-gate  */
171*0Sstevel@tonic-gate #ifdef _LP64
172*0Sstevel@tonic-gate #define	FSINFO_MNTLEN	48
173*0Sstevel@tonic-gate #else
174*0Sstevel@tonic-gate #define	FSINFO_MNTLEN	56
175*0Sstevel@tonic-gate #endif
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate /*ARGSUSED*/
178*0Sstevel@tonic-gate int
179*0Sstevel@tonic-gate fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	vfs_t vfs;
182*0Sstevel@tonic-gate 	int len;
183*0Sstevel@tonic-gate 	int opt_v = 0;
184*0Sstevel@tonic-gate 	char buf[MAXPATHLEN];
185*0Sstevel@tonic-gate 	char fsname[_ST_FSTYPSZ];
186*0Sstevel@tonic-gate 	mntopt_t *mntopts;
187*0Sstevel@tonic-gate 	size_t size;
188*0Sstevel@tonic-gate 	int i;
189*0Sstevel@tonic-gate 	int first = 1;
190*0Sstevel@tonic-gate 	char opt[MAX_MNTOPT_STR];
191*0Sstevel@tonic-gate 	uintptr_t global_zone;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
194*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) {
195*0Sstevel@tonic-gate 			mdb_warn("failed to walk file system list");
196*0Sstevel@tonic-gate 			return (DCMD_ERR);
197*0Sstevel@tonic-gate 		}
198*0Sstevel@tonic-gate 		return (DCMD_OK);
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
202*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
203*0Sstevel@tonic-gate 		return (DCMD_USAGE);
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
206*0Sstevel@tonic-gate 		mdb_printf("%<u>%?s %-15s %s%</u>\n",
207*0Sstevel@tonic-gate 		    "VFSP", "FS", "MOUNT");
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) {
210*0Sstevel@tonic-gate 		mdb_warn("failed to read vfs_t %p", addr);
211*0Sstevel@tonic-gate 		return (DCMD_ERR);
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf,
215*0Sstevel@tonic-gate 	    sizeof (buf))) <= 0)
216*0Sstevel@tonic-gate 		strcpy(buf, "??");
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	else if (!opt_v && (len >= FSINFO_MNTLEN))
219*0Sstevel@tonic-gate 		/*
220*0Sstevel@tonic-gate 		 * In normal mode, we truncate the path to keep the output
221*0Sstevel@tonic-gate 		 * clean.  In -v mode, we just print the full path.
222*0Sstevel@tonic-gate 		 */
223*0Sstevel@tonic-gate 		strcpy(&buf[FSINFO_MNTLEN - 4], "...");
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	if (read_fsname(addr, fsname) == -1)
226*0Sstevel@tonic-gate 		return (DCMD_ERR);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	mdb_printf("%0?p %-15s %s\n", addr, fsname, buf);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	if (!opt_v)
231*0Sstevel@tonic-gate 		return (DCMD_OK);
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	/*
234*0Sstevel@tonic-gate 	 * Print 'resource' string; this shows what we're mounted upon.
235*0Sstevel@tonic-gate 	 */
236*0Sstevel@tonic-gate 	if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf,
237*0Sstevel@tonic-gate 	    MAXPATHLEN) <= 0)
238*0Sstevel@tonic-gate 		strcpy(buf, "??");
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	mdb_printf("%?s %s\n", "R:", buf);
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/*
243*0Sstevel@tonic-gate 	 * Print mount options array; it sucks to be a mimic, but we copy
244*0Sstevel@tonic-gate 	 * the same logic as in mntvnops.c for adding zone= tags, and we
245*0Sstevel@tonic-gate 	 * don't bother with the obsolete dev= option.
246*0Sstevel@tonic-gate 	 */
247*0Sstevel@tonic-gate 	size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t);
248*0Sstevel@tonic-gate 	mntopts = mdb_alloc(size, UM_SLEEP | UM_GC);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if (mdb_vread(mntopts, size,
251*0Sstevel@tonic-gate 	    (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) {
252*0Sstevel@tonic-gate 		mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list);
253*0Sstevel@tonic-gate 		return (DCMD_ERR);
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) {
257*0Sstevel@tonic-gate 		if (mntopts[i].mo_flags & MO_SET) {
258*0Sstevel@tonic-gate 			if (mdb_readstr(opt, sizeof (opt),
259*0Sstevel@tonic-gate 			    (uintptr_t)mntopts[i].mo_name) == -1) {
260*0Sstevel@tonic-gate 				mdb_warn("failed to read mntopt name %p",
261*0Sstevel@tonic-gate 				    mntopts[i].mo_name);
262*0Sstevel@tonic-gate 				return (DCMD_ERR);
263*0Sstevel@tonic-gate 			}
264*0Sstevel@tonic-gate 			if (first) {
265*0Sstevel@tonic-gate 				mdb_printf("%?s ", "O:");
266*0Sstevel@tonic-gate 				first = 0;
267*0Sstevel@tonic-gate 			} else {
268*0Sstevel@tonic-gate 				mdb_printf(",");
269*0Sstevel@tonic-gate 			}
270*0Sstevel@tonic-gate 			mdb_printf("%s", opt);
271*0Sstevel@tonic-gate 			if (mntopts[i].mo_flags & MO_HASVALUE) {
272*0Sstevel@tonic-gate 				if (mdb_readstr(opt, sizeof (opt),
273*0Sstevel@tonic-gate 				    (uintptr_t)mntopts[i].mo_arg) == -1) {
274*0Sstevel@tonic-gate 					mdb_warn("failed to read mntopt "
275*0Sstevel@tonic-gate 					    "value %p", mntopts[i].mo_arg);
276*0Sstevel@tonic-gate 					return (DCMD_ERR);
277*0Sstevel@tonic-gate 				}
278*0Sstevel@tonic-gate 				mdb_printf("=%s", opt);
279*0Sstevel@tonic-gate 			}
280*0Sstevel@tonic-gate 		}
281*0Sstevel@tonic-gate 	}
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	if (mdb_readvar(&global_zone, "global_zone") == -1) {
284*0Sstevel@tonic-gate 		mdb_warn("failed to locate global_zone");
285*0Sstevel@tonic-gate 		return (DCMD_ERR);
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	if ((vfs.vfs_zone != NULL) &&
289*0Sstevel@tonic-gate 	    ((uintptr_t)vfs.vfs_zone != global_zone)) {
290*0Sstevel@tonic-gate 		zone_t z;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) {
293*0Sstevel@tonic-gate 			mdb_warn("failed to read zone");
294*0Sstevel@tonic-gate 			return (DCMD_ERR);
295*0Sstevel@tonic-gate 		}
296*0Sstevel@tonic-gate 		/*
297*0Sstevel@tonic-gate 		 * zone names are much shorter than MAX_MNTOPT_STR
298*0Sstevel@tonic-gate 		 */
299*0Sstevel@tonic-gate 		if (mdb_readstr(opt, sizeof (opt),
300*0Sstevel@tonic-gate 		    (uintptr_t)z.zone_name) == -1) {
301*0Sstevel@tonic-gate 			mdb_warn("failed to read zone name");
302*0Sstevel@tonic-gate 			return (DCMD_ERR);
303*0Sstevel@tonic-gate 		}
304*0Sstevel@tonic-gate 		if (first) {
305*0Sstevel@tonic-gate 			mdb_printf("%?s ", "O:");
306*0Sstevel@tonic-gate 		} else {
307*0Sstevel@tonic-gate 			mdb_printf(",");
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate 		mdb_printf("zone=%s", opt);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 	return (DCMD_OK);
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate #define	REALVP_DONE	0
316*0Sstevel@tonic-gate #define	REALVP_ERR	1
317*0Sstevel@tonic-gate #define	REALVP_CONTINUE	2
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate static int
320*0Sstevel@tonic-gate next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp)
321*0Sstevel@tonic-gate {
322*0Sstevel@tonic-gate 	char fsname[_ST_FSTYPSZ];
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	*outvp = invp;
325*0Sstevel@tonic-gate 	if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) {
326*0Sstevel@tonic-gate 		mdb_warn("failed to read vnode at %p", invp);
327*0Sstevel@tonic-gate 		return (REALVP_ERR);
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1)
331*0Sstevel@tonic-gate 		return (REALVP_ERR);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	/*
334*0Sstevel@tonic-gate 	 * We know how to do 'realvp' for as many filesystems as possible;
335*0Sstevel@tonic-gate 	 * for all other filesystems, we assume that the vp we are given
336*0Sstevel@tonic-gate 	 * is the realvp.  In the kernel, a realvp operation will sometimes
337*0Sstevel@tonic-gate 	 * dig through multiple layers.  Here, we only fetch the pointer
338*0Sstevel@tonic-gate 	 * to the next layer down.  This allows dcmds to print out the
339*0Sstevel@tonic-gate 	 * various layers.
340*0Sstevel@tonic-gate 	 */
341*0Sstevel@tonic-gate 	if (strcmp(fsname, "fifofs") == 0) {
342*0Sstevel@tonic-gate 		fifonode_t fn;
343*0Sstevel@tonic-gate 		if (mdb_vread(&fn, sizeof (fn),
344*0Sstevel@tonic-gate 		    (uintptr_t)outvn->v_data) == -1) {
345*0Sstevel@tonic-gate 			mdb_warn("failed to read fifonode");
346*0Sstevel@tonic-gate 			return (REALVP_ERR);
347*0Sstevel@tonic-gate 		}
348*0Sstevel@tonic-gate 		*outvp = (uintptr_t)fn.fn_realvp;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	} else if (strcmp(fsname, "namefs") == 0) {
351*0Sstevel@tonic-gate 		struct namenode nn;
352*0Sstevel@tonic-gate 		if (mdb_vread(&nn, sizeof (nn),
353*0Sstevel@tonic-gate 		    (uintptr_t)outvn->v_data) == -1) {
354*0Sstevel@tonic-gate 			mdb_warn("failed to read namenode");
355*0Sstevel@tonic-gate 			return (REALVP_ERR);
356*0Sstevel@tonic-gate 		}
357*0Sstevel@tonic-gate 		*outvp = (uintptr_t)nn.nm_filevp;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	} else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) {
360*0Sstevel@tonic-gate 		struct stdata stream;
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 		/*
363*0Sstevel@tonic-gate 		 * Sockets have a strange and different layering scheme; we
364*0Sstevel@tonic-gate 		 * hop over into the sockfs vnode (accessible via the stream
365*0Sstevel@tonic-gate 		 * head) if possible.
366*0Sstevel@tonic-gate 		 */
367*0Sstevel@tonic-gate 		if (mdb_vread(&stream, sizeof (stream),
368*0Sstevel@tonic-gate 		    (uintptr_t)outvn->v_stream) == -1) {
369*0Sstevel@tonic-gate 			mdb_warn("failed to read stream data");
370*0Sstevel@tonic-gate 			return (REALVP_ERR);
371*0Sstevel@tonic-gate 		}
372*0Sstevel@tonic-gate 		*outvp = (uintptr_t)stream.sd_vnode;
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if (*outvp == invp || *outvp == NULL)
376*0Sstevel@tonic-gate 		return (REALVP_DONE);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	return (REALVP_CONTINUE);
379*0Sstevel@tonic-gate }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate static void
382*0Sstevel@tonic-gate pfiles_print_addr(struct sockaddr *addr)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	struct sockaddr_in *s_in;
385*0Sstevel@tonic-gate 	struct sockaddr_un *s_un;
386*0Sstevel@tonic-gate 	struct sockaddr_in6 *s_in6;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	switch (addr->sa_family) {
389*0Sstevel@tonic-gate 	case AF_INET:
390*0Sstevel@tonic-gate 		/*LINTED: alignment*/
391*0Sstevel@tonic-gate 		s_in = (struct sockaddr_in *)addr;
392*0Sstevel@tonic-gate 		mdb_printf("AF_INET %I %d ",
393*0Sstevel@tonic-gate 		    s_in->sin_addr.s_addr, s_in->sin_port);
394*0Sstevel@tonic-gate 		break;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	case AF_INET6:
397*0Sstevel@tonic-gate 		/*LINTED: alignment*/
398*0Sstevel@tonic-gate 		s_in6 = (struct sockaddr_in6 *)addr;
399*0Sstevel@tonic-gate 		mdb_printf("AF_INET6 %N %d ",
400*0Sstevel@tonic-gate 		    &(s_in6->sin6_addr), s_in6->sin6_port);
401*0Sstevel@tonic-gate 		break;
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	case AF_UNIX:
404*0Sstevel@tonic-gate 		s_un = (struct sockaddr_un *)addr;
405*0Sstevel@tonic-gate 		mdb_printf("AF_UNIX %s ", s_un->sun_path);
406*0Sstevel@tonic-gate 		break;
407*0Sstevel@tonic-gate 	default:
408*0Sstevel@tonic-gate 		mdb_printf("AF_?? (%d) ", addr->sa_family);
409*0Sstevel@tonic-gate 		break;
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate static int
415*0Sstevel@tonic-gate pfiles_get_sonode(uintptr_t vp, struct sonode *sonode)
416*0Sstevel@tonic-gate {
417*0Sstevel@tonic-gate 	vnode_t v;
418*0Sstevel@tonic-gate 	struct stdata stream;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), vp) == -1) {
421*0Sstevel@tonic-gate 		mdb_warn("failed to read socket vnode");
422*0Sstevel@tonic-gate 		return (-1);
423*0Sstevel@tonic-gate 	}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	if (mdb_vread(&stream, sizeof (stream), (uintptr_t)v.v_stream) == -1) {
426*0Sstevel@tonic-gate 		mdb_warn("failed to read stream data");
427*0Sstevel@tonic-gate 		return (-1);
428*0Sstevel@tonic-gate 	}
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), (uintptr_t)stream.sd_vnode) == -1) {
431*0Sstevel@tonic-gate 		mdb_warn("failed to read stream vnode");
432*0Sstevel@tonic-gate 		return (-1);
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	if (mdb_vread(sonode, sizeof (struct sonode),
436*0Sstevel@tonic-gate 	    (uintptr_t)v.v_data) == -1) {
437*0Sstevel@tonic-gate 		mdb_warn("failed to read sonode");
438*0Sstevel@tonic-gate 		return (-1);
439*0Sstevel@tonic-gate 	}
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	return (0);
442*0Sstevel@tonic-gate }
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate /*
445*0Sstevel@tonic-gate  * Do some digging to get a reasonable pathname for this vnode. 'path'
446*0Sstevel@tonic-gate  * should point at a buffer of MAXPATHLEN in size.
447*0Sstevel@tonic-gate  */
448*0Sstevel@tonic-gate static int
449*0Sstevel@tonic-gate pfiles_dig_pathname(uintptr_t vp, char *path)
450*0Sstevel@tonic-gate {
451*0Sstevel@tonic-gate 	vnode_t v;
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	bzero(path, MAXPATHLEN);
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), vp) == -1) {
456*0Sstevel@tonic-gate 		mdb_warn("failed to read vnode");
457*0Sstevel@tonic-gate 		return (-1);
458*0Sstevel@tonic-gate 	}
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	if (v.v_path == NULL) {
461*0Sstevel@tonic-gate 		/*
462*0Sstevel@tonic-gate 		 * fifo's and doors are special.   Some have pathnames, and
463*0Sstevel@tonic-gate 		 * some do not.  And for these, it is pointless to go off to
464*0Sstevel@tonic-gate 		 * mdb_vnode2path, which is very slow.
465*0Sstevel@tonic-gate 		 *
466*0Sstevel@tonic-gate 		 * Event ports never have a pathname.
467*0Sstevel@tonic-gate 		 */
468*0Sstevel@tonic-gate 		if (v.v_type == VFIFO || v.v_type == VDOOR || v.v_type == VPORT)
469*0Sstevel@tonic-gate 			return (0);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 		/*
472*0Sstevel@tonic-gate 		 * For sockets, we won't find a path unless we print the path
473*0Sstevel@tonic-gate 		 * associated with the accessvp.
474*0Sstevel@tonic-gate 		 */
475*0Sstevel@tonic-gate 		if (v.v_type == VSOCK) {
476*0Sstevel@tonic-gate 			struct sonode sonode;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 			if (pfiles_get_sonode(vp, &sonode) == -1) {
479*0Sstevel@tonic-gate 				return (-1);
480*0Sstevel@tonic-gate 			}
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 			vp = (uintptr_t)sonode.so_accessvp;
483*0Sstevel@tonic-gate 		}
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/*
488*0Sstevel@tonic-gate 	 * mdb_vnode2path will print an error for us as needed, but not
489*0Sstevel@tonic-gate 	 * finding a pathname is not really an error, so we plow on.
490*0Sstevel@tonic-gate 	 */
491*0Sstevel@tonic-gate 	(void) mdb_vnode2path(vp, path, MAXPATHLEN);
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	/*
494*0Sstevel@tonic-gate 	 * A common problem is that device pathnames are prefixed with
495*0Sstevel@tonic-gate 	 * /dev/../devices/.  We just clean those up slightly:
496*0Sstevel@tonic-gate 	 * 	/dev/../devices/<mumble> --> /devices/<mumble>
497*0Sstevel@tonic-gate 	 * 	/dev/pts/../../devices/<mumble> --> /devices/<mumble>
498*0Sstevel@tonic-gate 	 */
499*0Sstevel@tonic-gate 	if (strncmp("/dev/../devices/", path, strlen("/dev/../devices/")) == 0)
500*0Sstevel@tonic-gate 		strcpy(path, path + 7);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	if (strncmp("/dev/pts/../../devices/", path,
503*0Sstevel@tonic-gate 	    strlen("/dev/pts/../../devices/")) == 0)
504*0Sstevel@tonic-gate 		strcpy(path, path + 14);
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	return (0);
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate const struct fs_type {
510*0Sstevel@tonic-gate 	int type;
511*0Sstevel@tonic-gate 	const char *name;
512*0Sstevel@tonic-gate } fs_types[] = {
513*0Sstevel@tonic-gate 	{ VNON,   "NON" },
514*0Sstevel@tonic-gate 	{ VREG,   "REG" },
515*0Sstevel@tonic-gate 	{ VDIR,   "DIR" },
516*0Sstevel@tonic-gate 	{ VBLK,   "BLK" },
517*0Sstevel@tonic-gate 	{ VCHR,   "CHR" },
518*0Sstevel@tonic-gate 	{ VLNK,   "LNK" },
519*0Sstevel@tonic-gate 	{ VFIFO,  "FIFO" },
520*0Sstevel@tonic-gate 	{ VDOOR,  "DOOR" },
521*0Sstevel@tonic-gate 	{ VPROC,  "PROC" },
522*0Sstevel@tonic-gate 	{ VSOCK,  "SOCK" },
523*0Sstevel@tonic-gate 	{ VPORT,  "PORT" },
524*0Sstevel@tonic-gate 	{ VBAD,   "BAD" }
525*0Sstevel@tonic-gate };
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate #define	NUM_FS_TYPES (sizeof (fs_types) / sizeof (struct fs_type))
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate struct pfiles_cbdata {
530*0Sstevel@tonic-gate 	int opt_p;
531*0Sstevel@tonic-gate 	int fd;
532*0Sstevel@tonic-gate };
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate static int
535*0Sstevel@tonic-gate pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
536*0Sstevel@tonic-gate {
537*0Sstevel@tonic-gate 	vnode_t v, layer_vn;
538*0Sstevel@tonic-gate 	int myfd = cb->fd;
539*0Sstevel@tonic-gate 	const char *type;
540*0Sstevel@tonic-gate 	char path[MAXPATHLEN];
541*0Sstevel@tonic-gate 	uintptr_t top_vnodep, realvpp;
542*0Sstevel@tonic-gate 	char fsname[_ST_FSTYPSZ];
543*0Sstevel@tonic-gate 	int err, i;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	cb->fd++;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	if (addr == NULL) {
548*0Sstevel@tonic-gate 		return (WALK_NEXT);
549*0Sstevel@tonic-gate 	}
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	top_vnodep = realvpp = (uintptr_t)f->f_vnode;
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	if (mdb_vread(&v, sizeof (v), realvpp) == -1) {
554*0Sstevel@tonic-gate 		mdb_warn("failed to read vnode");
555*0Sstevel@tonic-gate 		return (DCMD_ERR);
556*0Sstevel@tonic-gate 	}
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	type = "?";
559*0Sstevel@tonic-gate 	for (i = 0; i <= NUM_FS_TYPES; i++) {
560*0Sstevel@tonic-gate 		if (fs_types[i].type == v.v_type)
561*0Sstevel@tonic-gate 			type = fs_types[i].name;
562*0Sstevel@tonic-gate 	}
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	do {
565*0Sstevel@tonic-gate 		uintptr_t next_realvpp;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 		err = next_realvp(realvpp, &layer_vn, &next_realvpp);
568*0Sstevel@tonic-gate 		if (next_realvpp != NULL)
569*0Sstevel@tonic-gate 			realvpp = next_realvpp;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	} while (err == REALVP_CONTINUE);
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (err == REALVP_ERR) {
574*0Sstevel@tonic-gate 		mdb_warn("failed to do realvp() for %p", realvpp);
575*0Sstevel@tonic-gate 		return (DCMD_ERR);
576*0Sstevel@tonic-gate 	}
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1)
579*0Sstevel@tonic-gate 		return (DCMD_ERR);
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep);
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	if (cb->opt_p) {
584*0Sstevel@tonic-gate 		if (pfiles_dig_pathname(top_vnodep, path) == -1)
585*0Sstevel@tonic-gate 			return (DCMD_ERR);
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 		mdb_printf("%s\n", path);
588*0Sstevel@tonic-gate 		return (DCMD_OK);
589*0Sstevel@tonic-gate 	}
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	/*
592*0Sstevel@tonic-gate 	 * Sockets generally don't have interesting pathnames; we only
593*0Sstevel@tonic-gate 	 * show those in the '-p' view.
594*0Sstevel@tonic-gate 	 */
595*0Sstevel@tonic-gate 	path[0] = '\0';
596*0Sstevel@tonic-gate 	if (v.v_type != VSOCK) {
597*0Sstevel@tonic-gate 		if (pfiles_dig_pathname(top_vnodep, path) == -1)
598*0Sstevel@tonic-gate 			return (DCMD_ERR);
599*0Sstevel@tonic-gate 	}
600*0Sstevel@tonic-gate 	mdb_printf("%s%s", path, path[0] == '\0' ? "" : " ");
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	switch (v.v_type) {
603*0Sstevel@tonic-gate 	case VDOOR:
604*0Sstevel@tonic-gate 	{
605*0Sstevel@tonic-gate 		door_node_t doornode;
606*0Sstevel@tonic-gate 		proc_t pr;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 		if (mdb_vread(&doornode, sizeof (doornode),
609*0Sstevel@tonic-gate 		    (uintptr_t)layer_vn.v_data) == -1) {
610*0Sstevel@tonic-gate 			mdb_warn("failed to read door_node");
611*0Sstevel@tonic-gate 			return (DCMD_ERR);
612*0Sstevel@tonic-gate 		}
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 		if (mdb_vread(&pr, sizeof (pr),
615*0Sstevel@tonic-gate 		    (uintptr_t)doornode.door_target) == -1) {
616*0Sstevel@tonic-gate 			mdb_warn("failed to read door server process %p",
617*0Sstevel@tonic-gate 			    doornode.door_target);
618*0Sstevel@tonic-gate 			return (DCMD_ERR);
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 		mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm,
621*0Sstevel@tonic-gate 		    doornode.door_target);
622*0Sstevel@tonic-gate 		break;
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	case VSOCK:
626*0Sstevel@tonic-gate 	{
627*0Sstevel@tonic-gate 		struct sonode sonode;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 		if (pfiles_get_sonode(realvpp, &sonode) == -1)
630*0Sstevel@tonic-gate 			return (DCMD_ERR);
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 		/*
633*0Sstevel@tonic-gate 		 * If the address is cached in the sonode, use it; otherwise,
634*0Sstevel@tonic-gate 		 * we print nothing.
635*0Sstevel@tonic-gate 		 */
636*0Sstevel@tonic-gate 		if (sonode.so_state & SS_LADDR_VALID) {
637*0Sstevel@tonic-gate 			struct sockaddr *laddr =
638*0Sstevel@tonic-gate 			    mdb_alloc(sonode.so_laddr_len, UM_SLEEP);
639*0Sstevel@tonic-gate 			if (mdb_vread(laddr, sonode.so_laddr_len,
640*0Sstevel@tonic-gate 			    (uintptr_t)sonode.so_laddr_sa) == -1) {
641*0Sstevel@tonic-gate 				mdb_warn("failed to read sonode socket addr");
642*0Sstevel@tonic-gate 				return (DCMD_ERR);
643*0Sstevel@tonic-gate 			}
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 			mdb_printf("socket: ");
646*0Sstevel@tonic-gate 			pfiles_print_addr(laddr);
647*0Sstevel@tonic-gate 		}
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 		if (sonode.so_state & SS_FADDR_VALID) {
650*0Sstevel@tonic-gate 			struct sockaddr *faddr =
651*0Sstevel@tonic-gate 			    mdb_alloc(sonode.so_faddr_len, UM_SLEEP);
652*0Sstevel@tonic-gate 			if (mdb_vread(faddr, sonode.so_faddr_len,
653*0Sstevel@tonic-gate 			    (uintptr_t)sonode.so_faddr_sa) == -1) {
654*0Sstevel@tonic-gate 				mdb_warn("failed to read sonode remote addr");
655*0Sstevel@tonic-gate 				return (DCMD_ERR);
656*0Sstevel@tonic-gate 			}
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 			mdb_printf("remote: ");
659*0Sstevel@tonic-gate 			pfiles_print_addr(faddr);
660*0Sstevel@tonic-gate 		}
661*0Sstevel@tonic-gate 		break;
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	case VPORT:
665*0Sstevel@tonic-gate 		mdb_printf("[event port (port=%p)]", v.v_data);
666*0Sstevel@tonic-gate 		break;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	case VPROC:
669*0Sstevel@tonic-gate 	{
670*0Sstevel@tonic-gate 		prnode_t prnode;
671*0Sstevel@tonic-gate 		prcommon_t prcommon;
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 		if (mdb_vread(&prnode, sizeof (prnode),
674*0Sstevel@tonic-gate 		    (uintptr_t)layer_vn.v_data) == -1) {
675*0Sstevel@tonic-gate 			mdb_warn("failed to read prnode");
676*0Sstevel@tonic-gate 			return (DCMD_ERR);
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 		if (mdb_vread(&prcommon, sizeof (prcommon),
680*0Sstevel@tonic-gate 		    (uintptr_t)prnode.pr_common) == -1) {
681*0Sstevel@tonic-gate 			mdb_warn("failed to read prcommon %p",
682*0Sstevel@tonic-gate 			    prnode.pr_common);
683*0Sstevel@tonic-gate 			return (DCMD_ERR);
684*0Sstevel@tonic-gate 		}
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 		mdb_printf("(proc=%p)", prcommon.prc_proc);
687*0Sstevel@tonic-gate 		break;
688*0Sstevel@tonic-gate 	}
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	default:
691*0Sstevel@tonic-gate 		break;
692*0Sstevel@tonic-gate 	}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	mdb_printf("\n");
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	return (WALK_NEXT);
698*0Sstevel@tonic-gate }
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate static int
701*0Sstevel@tonic-gate file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
702*0Sstevel@tonic-gate {
703*0Sstevel@tonic-gate 	int myfd = cb->fd;
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	cb->fd++;
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	if (addr == NULL) {
708*0Sstevel@tonic-gate 		return (WALK_NEXT);
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	/*
712*0Sstevel@tonic-gate 	 * We really need 20 digits to print a 64-bit offset_t, but this
713*0Sstevel@tonic-gate 	 * is exceedingly rare, so we cheat and assume a column width of 10
714*0Sstevel@tonic-gate 	 * digits, in order to fit everything cleanly into 80 columns.
715*0Sstevel@tonic-gate 	 */
716*0Sstevel@tonic-gate 	mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n",
717*0Sstevel@tonic-gate 	    addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred,
718*0Sstevel@tonic-gate 	    f->f_count);
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	return (WALK_NEXT);
721*0Sstevel@tonic-gate }
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate int
724*0Sstevel@tonic-gate pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
725*0Sstevel@tonic-gate {
726*0Sstevel@tonic-gate 	int opt_f = 0;
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	struct pfiles_cbdata cb;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	bzero(&cb, sizeof (cb));
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
733*0Sstevel@tonic-gate 		return (DCMD_USAGE);
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
736*0Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p,
737*0Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc)
738*0Sstevel@tonic-gate 		return (DCMD_USAGE);
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	if (opt_f) {
741*0Sstevel@tonic-gate 		mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE",
742*0Sstevel@tonic-gate 		    "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT");
743*0Sstevel@tonic-gate 		if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb,
744*0Sstevel@tonic-gate 		    addr) == -1) {
745*0Sstevel@tonic-gate 			mdb_warn("failed to walk 'allfile'");
746*0Sstevel@tonic-gate 			return (DCMD_ERR);
747*0Sstevel@tonic-gate 		}
748*0Sstevel@tonic-gate 	} else {
749*0Sstevel@tonic-gate 		mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE");
750*0Sstevel@tonic-gate 		if (cb.opt_p)
751*0Sstevel@tonic-gate 			mdb_printf("PATH");
752*0Sstevel@tonic-gate 		else
753*0Sstevel@tonic-gate 			mdb_printf("INFO");
754*0Sstevel@tonic-gate 		mdb_printf("%</u>\n");
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 		if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb,
757*0Sstevel@tonic-gate 		    addr) == -1) {
758*0Sstevel@tonic-gate 			mdb_warn("failed to walk 'allfile'");
759*0Sstevel@tonic-gate 			return (DCMD_ERR);
760*0Sstevel@tonic-gate 		}
761*0Sstevel@tonic-gate 	}
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	return (DCMD_OK);
765*0Sstevel@tonic-gate }
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate void
768*0Sstevel@tonic-gate pfiles_help(void)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate 	mdb_printf(
771*0Sstevel@tonic-gate 	    "Given the address of a process, print information about files\n"
772*0Sstevel@tonic-gate 	    "which the process has open.  By default, this includes decoded\n"
773*0Sstevel@tonic-gate 	    "information about the file depending on file and filesystem type\n"
774*0Sstevel@tonic-gate 	    "\n"
775*0Sstevel@tonic-gate 	    "\t-p\tPathnames; omit decoded information.  Only display "
776*0Sstevel@tonic-gate 	    "pathnames\n"
777*0Sstevel@tonic-gate 	    "\t-f\tfile_t view; show the file_t structure corresponding to "
778*0Sstevel@tonic-gate 	    "the fd\n");
779*0Sstevel@tonic-gate }
780