xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/vfs.c (revision bd670b35a010421b6e1a5536c34453a827007c81)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <mdb/mdb_modapi.h>
27 #include <mdb/mdb_ks.h>
28 
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/door.h>
32 #include <sys/file.h>
33 #include <sys/mount.h>
34 #include <sys/proc.h>
35 #include <sys/procfs.h>
36 #include <sys/proc/prdata.h>
37 #include <sys/stat.h>
38 #include <sys/vfs.h>
39 #include <sys/vnode.h>
40 #include <sys/fs/snode.h>
41 #include <sys/fs/fifonode.h>
42 #include <sys/fs/namenode.h>
43 #include <sys/socket.h>
44 #include <sys/stropts.h>
45 #include <sys/socketvar.h>
46 #include <sys/strsubr.h>
47 #include <sys/un.h>
48 #include <fs/sockfs/socktpi_impl.h>
49 #include <inet/ipclassifier.h>
50 #include <inet/ip_if.h>
51 #include <inet/sctp/sctp_impl.h>
52 #include <inet/sctp/sctp_addr.h>
53 
54 int
55 vfs_walk_init(mdb_walk_state_t *wsp)
56 {
57 	if (wsp->walk_addr == NULL &&
58 	    mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
59 		mdb_warn("failed to read 'rootvfs'");
60 		return (WALK_ERR);
61 	}
62 
63 	wsp->walk_data = (void *)wsp->walk_addr;
64 	return (WALK_NEXT);
65 }
66 
67 int
68 vfs_walk_step(mdb_walk_state_t *wsp)
69 {
70 	vfs_t vfs;
71 	int status;
72 
73 	if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) {
74 		mdb_warn("failed to read vfs_t at %p", wsp->walk_addr);
75 		return (WALK_DONE);
76 	}
77 
78 	status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata);
79 
80 	if (vfs.vfs_next == wsp->walk_data)
81 		return (WALK_DONE);
82 
83 	wsp->walk_addr = (uintptr_t)vfs.vfs_next;
84 
85 	return (status);
86 }
87 
88 /*
89  * Utility routine to read in a filesystem name given a vfs pointer.  If
90  * no vfssw entry for the vfs is available (as is the case with some pseudo-
91  * filesystems), we check against some known problem fs's: doorfs and
92  * portfs.  If that fails, we try to guess the filesystem name using
93  * symbol names.  fsname should be a buffer of size _ST_FSTYPSZ.
94  */
95 static int
96 read_fsname(uintptr_t vfsp, char *fsname)
97 {
98 	vfs_t vfs;
99 	struct vfssw vfssw_entry;
100 	GElf_Sym vfssw_sym, test_sym;
101 	char testname[MDB_SYM_NAMLEN];
102 
103 	if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) {
104 		mdb_warn("failed to read vfs %p", vfsp);
105 		return (-1);
106 	}
107 
108 	if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) {
109 		mdb_warn("failed to find vfssw");
110 		return (-1);
111 	}
112 
113 	/*
114 	 * vfssw is an array; we need vfssw[vfs.vfs_fstype].
115 	 */
116 	if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry),
117 	    vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype))
118 	    == -1) {
119 		mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype);
120 		return (-1);
121 	}
122 
123 	if (vfs.vfs_fstype != 0) {
124 		if (mdb_readstr(fsname, _ST_FSTYPSZ,
125 		    (uintptr_t)vfssw_entry.vsw_name) == -1) {
126 			mdb_warn("failed to find fs name %p",
127 			    vfssw_entry.vsw_name);
128 			return (-1);
129 		}
130 		return (0);
131 	}
132 
133 	/*
134 	 * Do precise detection for certain filesystem types that we
135 	 * know do not appear in vfssw[], and that we depend upon in other
136 	 * parts of the code: doorfs and portfs.
137 	 */
138 	if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) {
139 		if (test_sym.st_value == vfsp) {
140 			strcpy(fsname, "doorfs");
141 			return (0);
142 		}
143 	}
144 	if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) {
145 		if (test_sym.st_value == vfsp) {
146 			strcpy(fsname, "portfs");
147 			return (0);
148 		}
149 	}
150 
151 	/*
152 	 * Heuristic detection for other filesystems that don't have a
153 	 * vfssw[] entry.  These tend to be named <fsname>_vfs, so we do a
154 	 * lookup_by_addr and see if we find a symbol of that name.
155 	 */
156 	if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname),
157 	    &test_sym) != -1) {
158 		if ((strlen(testname) > 4) &&
159 		    (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) {
160 			testname[strlen(testname) - 4] = '\0';
161 			strncpy(fsname, testname, _ST_FSTYPSZ);
162 			return (0);
163 		}
164 	}
165 
166 	mdb_warn("unknown filesystem type for vfs %p", vfsp);
167 	return (-1);
168 }
169 
170 /*
171  * Column widths for mount point display in ::fsinfo output.
172  */
173 #ifdef _LP64
174 #define	FSINFO_MNTLEN	48
175 #else
176 #define	FSINFO_MNTLEN	56
177 #endif
178 
179 /* ARGSUSED */
180 int
181 fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
182 {
183 	vfs_t vfs;
184 	int len;
185 	int opt_v = 0;
186 	char buf[MAXPATHLEN];
187 	char fsname[_ST_FSTYPSZ];
188 	mntopt_t *mntopts;
189 	size_t size;
190 	int i;
191 	int first = 1;
192 	char opt[MAX_MNTOPT_STR];
193 	uintptr_t global_zone;
194 
195 	if (!(flags & DCMD_ADDRSPEC)) {
196 		if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) {
197 			mdb_warn("failed to walk file system list");
198 			return (DCMD_ERR);
199 		}
200 		return (DCMD_OK);
201 	}
202 
203 	if (mdb_getopts(argc, argv,
204 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
205 		return (DCMD_USAGE);
206 
207 	if (DCMD_HDRSPEC(flags))
208 		mdb_printf("%<u>%?s %-15s %s%</u>\n",
209 		    "VFSP", "FS", "MOUNT");
210 
211 	if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) {
212 		mdb_warn("failed to read vfs_t %p", addr);
213 		return (DCMD_ERR);
214 	}
215 
216 	if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf,
217 	    sizeof (buf))) <= 0)
218 		strcpy(buf, "??");
219 
220 	else if (!opt_v && (len >= FSINFO_MNTLEN))
221 		/*
222 		 * In normal mode, we truncate the path to keep the output
223 		 * clean.  In -v mode, we just print the full path.
224 		 */
225 		strcpy(&buf[FSINFO_MNTLEN - 4], "...");
226 
227 	if (read_fsname(addr, fsname) == -1)
228 		return (DCMD_ERR);
229 
230 	mdb_printf("%0?p %-15s %s\n", addr, fsname, buf);
231 
232 	if (!opt_v)
233 		return (DCMD_OK);
234 
235 	/*
236 	 * Print 'resource' string; this shows what we're mounted upon.
237 	 */
238 	if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf,
239 	    MAXPATHLEN) <= 0)
240 		strcpy(buf, "??");
241 
242 	mdb_printf("%?s %s\n", "R:", buf);
243 
244 	/*
245 	 * Print mount options array; it sucks to be a mimic, but we copy
246 	 * the same logic as in mntvnops.c for adding zone= tags, and we
247 	 * don't bother with the obsolete dev= option.
248 	 */
249 	size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t);
250 	mntopts = mdb_alloc(size, UM_SLEEP | UM_GC);
251 
252 	if (mdb_vread(mntopts, size,
253 	    (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) {
254 		mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list);
255 		return (DCMD_ERR);
256 	}
257 
258 	for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) {
259 		if (mntopts[i].mo_flags & MO_SET) {
260 			if (mdb_readstr(opt, sizeof (opt),
261 			    (uintptr_t)mntopts[i].mo_name) == -1) {
262 				mdb_warn("failed to read mntopt name %p",
263 				    mntopts[i].mo_name);
264 				return (DCMD_ERR);
265 			}
266 			if (first) {
267 				mdb_printf("%?s ", "O:");
268 				first = 0;
269 			} else {
270 				mdb_printf(",");
271 			}
272 			mdb_printf("%s", opt);
273 			if (mntopts[i].mo_flags & MO_HASVALUE) {
274 				if (mdb_readstr(opt, sizeof (opt),
275 				    (uintptr_t)mntopts[i].mo_arg) == -1) {
276 					mdb_warn("failed to read mntopt "
277 					    "value %p", mntopts[i].mo_arg);
278 					return (DCMD_ERR);
279 				}
280 				mdb_printf("=%s", opt);
281 			}
282 		}
283 	}
284 
285 	if (mdb_readvar(&global_zone, "global_zone") == -1) {
286 		mdb_warn("failed to locate global_zone");
287 		return (DCMD_ERR);
288 	}
289 
290 	if ((vfs.vfs_zone != NULL) &&
291 	    ((uintptr_t)vfs.vfs_zone != global_zone)) {
292 		zone_t z;
293 
294 		if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) {
295 			mdb_warn("failed to read zone");
296 			return (DCMD_ERR);
297 		}
298 		/*
299 		 * zone names are much shorter than MAX_MNTOPT_STR
300 		 */
301 		if (mdb_readstr(opt, sizeof (opt),
302 		    (uintptr_t)z.zone_name) == -1) {
303 			mdb_warn("failed to read zone name");
304 			return (DCMD_ERR);
305 		}
306 		if (first) {
307 			mdb_printf("%?s ", "O:");
308 		} else {
309 			mdb_printf(",");
310 		}
311 		mdb_printf("zone=%s", opt);
312 	}
313 	return (DCMD_OK);
314 }
315 
316 
317 #define	REALVP_DONE	0
318 #define	REALVP_ERR	1
319 #define	REALVP_CONTINUE	2
320 
321 static int
322 next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp)
323 {
324 	char fsname[_ST_FSTYPSZ];
325 
326 	*outvp = invp;
327 	if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) {
328 		mdb_warn("failed to read vnode at %p", invp);
329 		return (REALVP_ERR);
330 	}
331 
332 	if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1)
333 		return (REALVP_ERR);
334 
335 	/*
336 	 * We know how to do 'realvp' for as many filesystems as possible;
337 	 * for all other filesystems, we assume that the vp we are given
338 	 * is the realvp.  In the kernel, a realvp operation will sometimes
339 	 * dig through multiple layers.  Here, we only fetch the pointer
340 	 * to the next layer down.  This allows dcmds to print out the
341 	 * various layers.
342 	 */
343 	if (strcmp(fsname, "fifofs") == 0) {
344 		fifonode_t fn;
345 		if (mdb_vread(&fn, sizeof (fn),
346 		    (uintptr_t)outvn->v_data) == -1) {
347 			mdb_warn("failed to read fifonode");
348 			return (REALVP_ERR);
349 		}
350 		*outvp = (uintptr_t)fn.fn_realvp;
351 
352 	} else if (strcmp(fsname, "namefs") == 0) {
353 		struct namenode nn;
354 		if (mdb_vread(&nn, sizeof (nn),
355 		    (uintptr_t)outvn->v_data) == -1) {
356 			mdb_warn("failed to read namenode");
357 			return (REALVP_ERR);
358 		}
359 		*outvp = (uintptr_t)nn.nm_filevp;
360 
361 	} else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) {
362 		struct stdata stream;
363 
364 		/*
365 		 * Sockets have a strange and different layering scheme; we
366 		 * hop over into the sockfs vnode (accessible via the stream
367 		 * head) if possible.
368 		 */
369 		if (mdb_vread(&stream, sizeof (stream),
370 		    (uintptr_t)outvn->v_stream) == -1) {
371 			mdb_warn("failed to read stream data");
372 			return (REALVP_ERR);
373 		}
374 		*outvp = (uintptr_t)stream.sd_vnode;
375 	}
376 
377 	if (*outvp == invp || *outvp == NULL)
378 		return (REALVP_DONE);
379 
380 	return (REALVP_CONTINUE);
381 }
382 
383 static void
384 pfiles_print_addr(struct sockaddr *addr)
385 {
386 	struct sockaddr_in *s_in;
387 	struct sockaddr_un *s_un;
388 	struct sockaddr_in6 *s_in6;
389 	in_port_t port;
390 
391 	switch (addr->sa_family) {
392 	case AF_INET:
393 		/* LINTED: alignment */
394 		s_in = (struct sockaddr_in *)addr;
395 		mdb_nhconvert(&port, &s_in->sin_port, sizeof (port));
396 		mdb_printf("AF_INET %I %d ", s_in->sin_addr.s_addr, port);
397 		break;
398 
399 	case AF_INET6:
400 		/* LINTED: alignment */
401 		s_in6 = (struct sockaddr_in6 *)addr;
402 		mdb_nhconvert(&port, &s_in6->sin6_port, sizeof (port));
403 		mdb_printf("AF_INET6 %N %d ", &(s_in6->sin6_addr), port);
404 		break;
405 
406 	case AF_UNIX:
407 		s_un = (struct sockaddr_un *)addr;
408 		mdb_printf("AF_UNIX %s ", s_un->sun_path);
409 		break;
410 	default:
411 		mdb_printf("AF_?? (%d) ", addr->sa_family);
412 		break;
413 	}
414 }
415 
416 static int
417 pfiles_get_sonode(vnode_t *v_sock, struct sonode *sonode)
418 {
419 	if (mdb_vread(sonode, sizeof (struct sonode),
420 	    (uintptr_t)v_sock->v_data) == -1) {
421 		mdb_warn("failed to read sonode");
422 		return (-1);
423 	}
424 
425 	return (0);
426 }
427 
428 static int
429 pfiles_get_tpi_sonode(vnode_t *v_sock, sotpi_sonode_t *sotpi_sonode)
430 {
431 
432 	struct stdata stream;
433 
434 	if (mdb_vread(&stream, sizeof (stream),
435 	    (uintptr_t)v_sock->v_stream) == -1) {
436 		mdb_warn("failed to read stream data");
437 		return (-1);
438 	}
439 
440 	if (mdb_vread(v_sock, sizeof (vnode_t),
441 	    (uintptr_t)stream.sd_vnode) == -1) {
442 		mdb_warn("failed to read stream vnode");
443 		return (-1);
444 	}
445 
446 	if (mdb_vread(sotpi_sonode, sizeof (sotpi_sonode_t),
447 	    (uintptr_t)v_sock->v_data) == -1) {
448 		mdb_warn("failed to read sotpi_sonode");
449 		return (-1);
450 	}
451 
452 	return (0);
453 }
454 
455 /*
456  * Do some digging to get a reasonable pathname for this vnode. 'path'
457  * should point at a buffer of MAXPATHLEN in size.
458  */
459 static int
460 pfiles_dig_pathname(uintptr_t vp, char *path)
461 {
462 	vnode_t v;
463 
464 	bzero(path, MAXPATHLEN);
465 
466 	if (mdb_vread(&v, sizeof (v), vp) == -1) {
467 		mdb_warn("failed to read vnode");
468 		return (-1);
469 	}
470 
471 	if (v.v_path == NULL) {
472 		/*
473 		 * fifo's and doors are special.   Some have pathnames, and
474 		 * some do not.  And for these, it is pointless to go off to
475 		 * mdb_vnode2path, which is very slow.
476 		 *
477 		 * Event ports never have a pathname.
478 		 */
479 		if (v.v_type == VFIFO || v.v_type == VDOOR || v.v_type == VPORT)
480 			return (0);
481 
482 		/*
483 		 * For sockets, we won't find a path unless we print the path
484 		 * associated with transport's STREAM device.
485 		 */
486 		if (v.v_type == VSOCK) {
487 			struct sonode sonode;
488 			struct sockparams sockparams;
489 
490 			if (pfiles_get_sonode(&v, &sonode) == -1) {
491 				return (-1);
492 			}
493 			if (mdb_vread(&sockparams, sizeof (sockparams),
494 			    (uintptr_t)sonode.so_sockparams) == -1) {
495 				mdb_warn("failed to read sockparams");
496 				return (-1);
497 			}
498 
499 			if (!SOCK_IS_NONSTR(&sonode)) {
500 				vp = (uintptr_t)
501 				    sockparams.sp_sdev_info.sd_vnode;
502 			} else {
503 				vp = NULL;
504 			}
505 		}
506 	}
507 
508 
509 	/*
510 	 * mdb_vnode2path will print an error for us as needed, but not
511 	 * finding a pathname is not really an error, so we plow on.
512 	 */
513 	(void) mdb_vnode2path(vp, path, MAXPATHLEN);
514 
515 	/*
516 	 * A common problem is that device pathnames are prefixed with
517 	 * /dev/../devices/.  We just clean those up slightly:
518 	 * 	/dev/../devices/<mumble> --> /devices/<mumble>
519 	 * 	/dev/pts/../../devices/<mumble> --> /devices/<mumble>
520 	 */
521 	if (strncmp("/dev/../devices/", path, strlen("/dev/../devices/")) == 0)
522 		strcpy(path, path + 7);
523 
524 	if (strncmp("/dev/pts/../../devices/", path,
525 	    strlen("/dev/pts/../../devices/")) == 0)
526 		strcpy(path, path + 14);
527 
528 	return (0);
529 }
530 
531 const struct fs_type {
532 	int type;
533 	const char *name;
534 } fs_types[] = {
535 	{ VNON,   "NON" },
536 	{ VREG,   "REG" },
537 	{ VDIR,   "DIR" },
538 	{ VBLK,   "BLK" },
539 	{ VCHR,   "CHR" },
540 	{ VLNK,   "LNK" },
541 	{ VFIFO,  "FIFO" },
542 	{ VDOOR,  "DOOR" },
543 	{ VPROC,  "PROC" },
544 	{ VSOCK,  "SOCK" },
545 	{ VPORT,  "PORT" },
546 	{ VBAD,   "BAD" }
547 };
548 
549 #define	NUM_FS_TYPES (sizeof (fs_types) / sizeof (struct fs_type))
550 
551 struct pfiles_cbdata {
552 	int opt_p;
553 	int fd;
554 };
555 
556 #define	list_d2l(a, obj) ((list_node_t *)(((char *)obj) + (a)->list_offset))
557 #define	list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
558 
559 /*
560  * SCTP interface for geting the first source address of a sctp_t.
561  */
562 int
563 sctp_getsockaddr(sctp_t *sctp, struct sockaddr *addr)
564 {
565 	int			err = -1;
566 	int			i;
567 	int			l;
568 	sctp_saddr_ipif_t	*pobj;
569 	sctp_saddr_ipif_t	obj;
570 	size_t			added = 0;
571 	sin6_t			*sin6;
572 	sin_t			*sin4;
573 	int			scanned = 0;
574 	boolean_t		skip_lback = B_FALSE;
575 	conn_t			*connp = sctp->sctp_connp;
576 
577 	addr->sa_family = connp->conn_family;
578 	if (sctp->sctp_nsaddrs == 0)
579 		goto done;
580 
581 	/*
582 	 * Skip loopback addresses for non-loopback assoc.
583 	 */
584 	if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback) {
585 		skip_lback = B_TRUE;
586 	}
587 
588 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
589 		if (sctp->sctp_saddrs[i].ipif_count == 0)
590 			continue;
591 
592 		pobj = list_object(&sctp->sctp_saddrs[i].sctp_ipif_list,
593 		    sctp->sctp_saddrs[i].sctp_ipif_list.list_head.list_next);
594 		if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t),
595 		    (uintptr_t)pobj) == -1) {
596 			mdb_warn("failed to read sctp_saddr_ipif_t");
597 			return (err);
598 		}
599 
600 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
601 			sctp_ipif_t	ipif;
602 			in6_addr_t	laddr;
603 			list_node_t 	*pnode;
604 			list_node_t	node;
605 
606 			if (mdb_vread(&ipif, sizeof (sctp_ipif_t),
607 			    (uintptr_t)obj.saddr_ipifp) == -1) {
608 				mdb_warn("failed to read sctp_ipif_t");
609 				return (err);
610 			}
611 			laddr = ipif.sctp_ipif_saddr;
612 
613 			scanned++;
614 			if ((ipif.sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
615 			    SCTP_DONT_SRC(&obj) ||
616 			    (ipif.sctp_ipif_ill->sctp_ill_flags &
617 			    PHYI_LOOPBACK) && skip_lback) {
618 				if (scanned >= sctp->sctp_nsaddrs)
619 					goto done;
620 
621 				/* LINTED: alignment */
622 				pnode = list_d2l(&sctp->sctp_saddrs[i].
623 				    sctp_ipif_list, pobj);
624 				if (mdb_vread(&node, sizeof (list_node_t),
625 				    (uintptr_t)pnode) == -1) {
626 					mdb_warn("failed to read list_node_t");
627 					return (err);
628 				}
629 				pobj = list_object(&sctp->sctp_saddrs[i].
630 				    sctp_ipif_list, node.list_next);
631 				if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t),
632 				    (uintptr_t)pobj) == -1) {
633 					mdb_warn("failed to read "
634 					    "sctp_saddr_ipif_t");
635 					return (err);
636 				}
637 				continue;
638 			}
639 
640 			switch (connp->conn_family) {
641 			case AF_INET:
642 				/* LINTED: alignment */
643 				sin4 = (sin_t *)addr;
644 				if ((sctp->sctp_state <= SCTPS_LISTEN) &&
645 				    sctp->sctp_bound_to_all) {
646 					sin4->sin_addr.s_addr = INADDR_ANY;
647 					sin4->sin_port = connp->conn_lport;
648 				} else {
649 					sin4 += added;
650 					sin4->sin_family = AF_INET;
651 					sin4->sin_port = connp->conn_lport;
652 					IN6_V4MAPPED_TO_INADDR(&laddr,
653 					    &sin4->sin_addr);
654 				}
655 				break;
656 
657 			case AF_INET6:
658 				/* LINTED: alignment */
659 				sin6 = (sin6_t *)addr;
660 				if ((sctp->sctp_state <= SCTPS_LISTEN) &&
661 				    sctp->sctp_bound_to_all) {
662 					bzero(&sin6->sin6_addr,
663 					    sizeof (sin6->sin6_addr));
664 					sin6->sin6_port = connp->conn_lport;
665 				} else {
666 					sin6 += added;
667 					sin6->sin6_family = AF_INET6;
668 					sin6->sin6_port = connp->conn_lport;
669 					sin6->sin6_addr = laddr;
670 				}
671 				sin6->sin6_flowinfo = connp->conn_flowinfo;
672 				sin6->sin6_scope_id = 0;
673 				sin6->__sin6_src_id = 0;
674 				break;
675 			}
676 			added++;
677 			if (added >= 1) {
678 				err = 0;
679 				goto done;
680 			}
681 			if (scanned >= sctp->sctp_nsaddrs)
682 				goto done;
683 
684 			/* LINTED: alignment */
685 			pnode = list_d2l(&sctp->sctp_saddrs[i].sctp_ipif_list,
686 			    pobj);
687 			if (mdb_vread(&node, sizeof (list_node_t),
688 			    (uintptr_t)pnode) == -1) {
689 				mdb_warn("failed to read list_node_t");
690 				return (err);
691 			}
692 			pobj = list_object(&sctp->sctp_saddrs[i].
693 			    sctp_ipif_list, node.list_next);
694 			if (mdb_vread(&obj, sizeof (sctp_saddr_ipif_t),
695 			    (uintptr_t)pobj) == -1) {
696 				mdb_warn("failed to read sctp_saddr_ipif_t");
697 				return (err);
698 			}
699 		}
700 	}
701 done:
702 	return (err);
703 }
704 
705 /*
706  * SCTP interface for geting the primary peer address of a sctp_t.
707  */
708 static int
709 sctp_getpeeraddr(sctp_t *sctp, struct sockaddr *addr)
710 {
711 	struct sockaddr_in	*sin4;
712 	struct sockaddr_in6	*sin6;
713 	sctp_faddr_t		sctp_primary;
714 	in6_addr_t		faddr;
715 	conn_t			*connp = sctp->sctp_connp;
716 
717 	if (sctp->sctp_faddrs == NULL)
718 		return (-1);
719 
720 	addr->sa_family = connp->conn_family;
721 	if (mdb_vread(&sctp_primary, sizeof (sctp_faddr_t),
722 	    (uintptr_t)sctp->sctp_primary) == -1) {
723 		mdb_warn("failed to read sctp primary faddr");
724 		return (-1);
725 	}
726 	faddr = sctp_primary.faddr;
727 
728 	switch (connp->conn_family) {
729 	case AF_INET:
730 		/* LINTED: alignment */
731 		sin4 = (struct sockaddr_in *)addr;
732 		IN6_V4MAPPED_TO_INADDR(&faddr, &sin4->sin_addr);
733 		sin4->sin_port = connp->conn_fport;
734 		sin4->sin_family = AF_INET;
735 		break;
736 
737 	case AF_INET6:
738 		/* LINTED: alignment */
739 		sin6 = (struct sockaddr_in6 *)addr;
740 		sin6->sin6_addr = faddr;
741 		sin6->sin6_port = connp->conn_fport;
742 		sin6->sin6_family = AF_INET6;
743 		sin6->sin6_flowinfo = 0;
744 		sin6->sin6_scope_id = 0;
745 		sin6->__sin6_src_id = 0;
746 		break;
747 	}
748 
749 	return (0);
750 }
751 
752 static int
753 tpi_sock_print(sotpi_sonode_t *sotpi_sonode)
754 {
755 	if (sotpi_sonode->st_info.sti_laddr_valid == 1) {
756 		struct sockaddr *laddr =
757 		    mdb_alloc(sotpi_sonode->st_info.sti_laddr_len, UM_SLEEP);
758 		if (mdb_vread(laddr, sotpi_sonode->st_info.sti_laddr_len,
759 		    (uintptr_t)sotpi_sonode->st_info.sti_laddr_sa) == -1) {
760 			mdb_warn("failed to read sotpi_sonode socket addr");
761 			return (-1);
762 		}
763 
764 		mdb_printf("socket: ");
765 		pfiles_print_addr(laddr);
766 	}
767 
768 	if (sotpi_sonode->st_info.sti_faddr_valid == 1) {
769 		struct sockaddr *faddr =
770 		    mdb_alloc(sotpi_sonode->st_info.sti_faddr_len, UM_SLEEP);
771 		if (mdb_vread(faddr, sotpi_sonode->st_info.sti_faddr_len,
772 		    (uintptr_t)sotpi_sonode->st_info.sti_faddr_sa) == -1) {
773 			mdb_warn("failed to read sotpi_sonode remote addr");
774 			return (-1);
775 		}
776 
777 		mdb_printf("remote: ");
778 		pfiles_print_addr(faddr);
779 	}
780 
781 	return (0);
782 }
783 
784 static int
785 tcpip_sock_print(struct sonode *socknode)
786 {
787 	switch (socknode->so_family) {
788 	case AF_INET:
789 	{
790 		conn_t conn_t;
791 		in_port_t port;
792 
793 		if (mdb_vread(&conn_t, sizeof (conn_t),
794 		    (uintptr_t)socknode->so_proto_handle) == -1) {
795 			mdb_warn("failed to read conn_t V4");
796 			return (-1);
797 		}
798 
799 		mdb_printf("socket: ");
800 		mdb_nhconvert(&port, &conn_t.conn_lport, sizeof (port));
801 		mdb_printf("AF_INET %I %d ", conn_t.conn_laddr_v4, port);
802 
803 		/*
804 		 * If this is a listening socket, we don't print
805 		 * the remote address.
806 		 */
807 		if (IPCL_IS_TCP(&conn_t) && IPCL_IS_BOUND(&conn_t) == 0 ||
808 		    IPCL_IS_UDP(&conn_t) && IPCL_IS_CONNECTED(&conn_t)) {
809 			mdb_printf("remote: ");
810 			mdb_nhconvert(&port, &conn_t.conn_fport, sizeof (port));
811 			mdb_printf("AF_INET %I %d ", conn_t.conn_faddr_v4,
812 			    port);
813 		}
814 
815 		break;
816 	}
817 
818 	case AF_INET6:
819 	{
820 		conn_t conn_t;
821 		in_port_t port;
822 
823 		if (mdb_vread(&conn_t, sizeof (conn_t),
824 		    (uintptr_t)socknode->so_proto_handle) == -1) {
825 			mdb_warn("failed to read conn_t V6");
826 			return (-1);
827 		}
828 
829 		mdb_printf("socket: ");
830 		mdb_nhconvert(&port, &conn_t.conn_lport, sizeof (port));
831 		mdb_printf("AF_INET6 %N %d ", &conn_t.conn_laddr_v4, port);
832 
833 		/*
834 		 * If this is a listening socket, we don't print
835 		 * the remote address.
836 		 */
837 		if (IPCL_IS_TCP(&conn_t) && IPCL_IS_BOUND(&conn_t) == 0 ||
838 		    IPCL_IS_UDP(&conn_t) && IPCL_IS_CONNECTED(&conn_t)) {
839 			mdb_printf("remote: ");
840 			mdb_nhconvert(&port, &conn_t.conn_fport, sizeof (port));
841 			mdb_printf("AF_INET6 %N %d ", &conn_t.conn_faddr_v6,
842 			    port);
843 		}
844 
845 		break;
846 	}
847 
848 	default:
849 		mdb_printf("AF_?? (%d)", socknode->so_family);
850 		break;
851 	}
852 
853 	return (0);
854 }
855 
856 static int
857 sctp_sock_print(struct sonode *socknode)
858 {
859 	sctp_t sctp_t;
860 	conn_t conns;
861 
862 	struct sockaddr *laddr = mdb_alloc(sizeof (struct sockaddr), UM_SLEEP);
863 	struct sockaddr *faddr = mdb_alloc(sizeof (struct sockaddr), UM_SLEEP);
864 
865 	if (mdb_vread(&sctp_t, sizeof (sctp_t),
866 	    (uintptr_t)socknode->so_proto_handle) == -1) {
867 		mdb_warn("failed to read sctp_t");
868 		return (-1);
869 	}
870 
871 	if (mdb_vread(&conns, sizeof (conn_t),
872 	    (uintptr_t)sctp_t.sctp_connp) == -1) {
873 		mdb_warn("failed to read conn_t at %p",
874 		    (uintptr_t)sctp_t.sctp_connp);
875 		return (-1);
876 	}
877 	sctp_t.sctp_connp = &conns;
878 
879 	if (sctp_getsockaddr(&sctp_t, laddr) == 0) {
880 		mdb_printf("socket:");
881 		pfiles_print_addr(laddr);
882 	}
883 	if (sctp_getpeeraddr(&sctp_t, faddr) == 0) {
884 		mdb_printf("remote:");
885 		pfiles_print_addr(faddr);
886 	}
887 
888 	return (0);
889 }
890 
891 /* ARGSUSED */
892 static int
893 sdp_sock_print(struct sonode *socknode)
894 {
895 	return (0);
896 }
897 
898 struct sock_print {
899 	int	family;
900 	int	type;
901 	int	pro;
902 	int	(*print)(struct sonode *socknode);
903 } sock_prints[] = {
904 	{ 2,	2,	0,	tcpip_sock_print },	/* /dev/tcp	*/
905 	{ 2,	2,	6,	tcpip_sock_print },	/* /dev/tcp	*/
906 	{ 26,	2,	0,	tcpip_sock_print },	/* /dev/tcp6	*/
907 	{ 26,	2,	6,	tcpip_sock_print },	/* /dev/tcp6	*/
908 	{ 2,	1,	0,	tcpip_sock_print },	/* /dev/udp	*/
909 	{ 2,	1,	17,	tcpip_sock_print },	/* /dev/udp	*/
910 	{ 26,	1,	0,	tcpip_sock_print },	/* /dev/udp6	*/
911 	{ 26,	1,	17,	tcpip_sock_print },	/* /dev/udp6	*/
912 	{ 2,	4,	0,	tcpip_sock_print },	/* /dev/rawip	*/
913 	{ 26,	4,	0,	tcpip_sock_print },	/* /dev/rawip6	*/
914 	{ 2,	2,	132,	sctp_sock_print },	/* /dev/sctp	*/
915 	{ 26,	2,	132,	sctp_sock_print },	/* /dev/sctp6	*/
916 	{ 2,	6,	132,	sctp_sock_print },	/* /dev/sctp	*/
917 	{ 26,	6,	132,	sctp_sock_print },	/* /dev/sctp6	*/
918 	{ 24,	4,	0,	tcpip_sock_print },	/* /dev/rts	*/
919 	{ 2,	2,	257,	sdp_sock_print },	/* /dev/sdp	*/
920 	{ 26,	2,	257,	sdp_sock_print },	/* /dev/sdp	*/
921 };
922 
923 #define	NUM_SOCK_PRINTS                                         \
924 	(sizeof (sock_prints) / sizeof (struct sock_print))
925 
926 static int
927 pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
928 {
929 	vnode_t v, layer_vn;
930 	int myfd = cb->fd;
931 	const char *type;
932 	char path[MAXPATHLEN];
933 	uintptr_t top_vnodep, realvpp;
934 	char fsname[_ST_FSTYPSZ];
935 	int err, i;
936 
937 	cb->fd++;
938 
939 	if (addr == NULL) {
940 		return (WALK_NEXT);
941 	}
942 
943 	top_vnodep = realvpp = (uintptr_t)f->f_vnode;
944 
945 	if (mdb_vread(&v, sizeof (v), realvpp) == -1) {
946 		mdb_warn("failed to read vnode");
947 		return (DCMD_ERR);
948 	}
949 
950 	type = "?";
951 	for (i = 0; i <= NUM_FS_TYPES; i++) {
952 		if (fs_types[i].type == v.v_type)
953 			type = fs_types[i].name;
954 	}
955 
956 	do {
957 		uintptr_t next_realvpp;
958 
959 		err = next_realvp(realvpp, &layer_vn, &next_realvpp);
960 		if (next_realvpp != NULL)
961 			realvpp = next_realvpp;
962 
963 	} while (err == REALVP_CONTINUE);
964 
965 	if (err == REALVP_ERR) {
966 		mdb_warn("failed to do realvp() for %p", realvpp);
967 		return (DCMD_ERR);
968 	}
969 
970 	if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1)
971 		return (DCMD_ERR);
972 
973 	mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep);
974 
975 	if (cb->opt_p) {
976 		if (pfiles_dig_pathname(top_vnodep, path) == -1)
977 			return (DCMD_ERR);
978 
979 		mdb_printf("%s\n", path);
980 		return (DCMD_OK);
981 	}
982 
983 	/*
984 	 * Sockets generally don't have interesting pathnames; we only
985 	 * show those in the '-p' view.
986 	 */
987 	path[0] = '\0';
988 	if (v.v_type != VSOCK) {
989 		if (pfiles_dig_pathname(top_vnodep, path) == -1)
990 			return (DCMD_ERR);
991 	}
992 	mdb_printf("%s%s", path, path[0] == '\0' ? "" : " ");
993 
994 	switch (v.v_type) {
995 	case VDOOR:
996 	{
997 		door_node_t doornode;
998 		proc_t pr;
999 
1000 		if (mdb_vread(&doornode, sizeof (doornode),
1001 		    (uintptr_t)layer_vn.v_data) == -1) {
1002 			mdb_warn("failed to read door_node");
1003 			return (DCMD_ERR);
1004 		}
1005 
1006 		if (mdb_vread(&pr, sizeof (pr),
1007 		    (uintptr_t)doornode.door_target) == -1) {
1008 			mdb_warn("failed to read door server process %p",
1009 			    doornode.door_target);
1010 			return (DCMD_ERR);
1011 		}
1012 		mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm,
1013 		    doornode.door_target);
1014 		break;
1015 	}
1016 
1017 	case VSOCK:
1018 	{
1019 		vnode_t v_sock;
1020 		struct sonode so;
1021 
1022 		if (mdb_vread(&v_sock, sizeof (v_sock), realvpp) == -1) {
1023 			mdb_warn("failed to read socket vnode");
1024 			return (DCMD_ERR);
1025 		}
1026 
1027 		/*
1028 		 * Sockets can be non-stream or stream, they have to be dealed
1029 		 * with differently.
1030 		 */
1031 		if (v_sock.v_stream == NULL) {
1032 			if (pfiles_get_sonode(&v_sock, &so) == -1)
1033 				return (DCMD_ERR);
1034 
1035 			/* Pick the proper methods. */
1036 			for (i = 0; i <= NUM_SOCK_PRINTS; i++) {
1037 				if ((sock_prints[i].family == so.so_family &&
1038 				    sock_prints[i].type == so.so_type &&
1039 				    sock_prints[i].pro == so.so_protocol) ||
1040 				    (sock_prints[i].family == so.so_family &&
1041 				    sock_prints[i].type == so.so_type &&
1042 				    so.so_type == SOCK_RAW)) {
1043 					if ((*sock_prints[i].print)(&so) == -1)
1044 						return (DCMD_ERR);
1045 				}
1046 			}
1047 		} else {
1048 			sotpi_sonode_t sotpi_sonode;
1049 
1050 			if (pfiles_get_sonode(&v_sock, &so) == -1)
1051 				return (DCMD_ERR);
1052 
1053 			/*
1054 			 * If the socket is a fallback socket, read its related
1055 			 * information separately; otherwise, read it as a whole
1056 			 * tpi socket.
1057 			 */
1058 			if (so.so_state & SS_FALLBACK_COMP) {
1059 				sotpi_sonode.st_sonode = so;
1060 
1061 				if (mdb_vread(&(sotpi_sonode.st_info),
1062 				    sizeof (sotpi_info_t),
1063 				    (uintptr_t)so.so_priv) == -1)
1064 					return (DCMD_ERR);
1065 			} else {
1066 				if (pfiles_get_tpi_sonode(&v_sock,
1067 				    &sotpi_sonode) == -1)
1068 					return (DCMD_ERR);
1069 			}
1070 
1071 			if (tpi_sock_print(&sotpi_sonode) == -1)
1072 				return (DCMD_ERR);
1073 		}
1074 
1075 		break;
1076 	}
1077 
1078 	case VPORT:
1079 		mdb_printf("[event port (port=%p)]", v.v_data);
1080 		break;
1081 
1082 	case VPROC:
1083 	{
1084 		prnode_t prnode;
1085 		prcommon_t prcommon;
1086 
1087 		if (mdb_vread(&prnode, sizeof (prnode),
1088 		    (uintptr_t)layer_vn.v_data) == -1) {
1089 			mdb_warn("failed to read prnode");
1090 			return (DCMD_ERR);
1091 		}
1092 
1093 		if (mdb_vread(&prcommon, sizeof (prcommon),
1094 		    (uintptr_t)prnode.pr_common) == -1) {
1095 			mdb_warn("failed to read prcommon %p",
1096 			    prnode.pr_common);
1097 			return (DCMD_ERR);
1098 		}
1099 
1100 		mdb_printf("(proc=%p)", prcommon.prc_proc);
1101 		break;
1102 	}
1103 
1104 	default:
1105 		break;
1106 	}
1107 
1108 	mdb_printf("\n");
1109 
1110 	return (WALK_NEXT);
1111 }
1112 
1113 static int
1114 file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
1115 {
1116 	int myfd = cb->fd;
1117 
1118 	cb->fd++;
1119 
1120 	if (addr == NULL) {
1121 		return (WALK_NEXT);
1122 	}
1123 
1124 	/*
1125 	 * We really need 20 digits to print a 64-bit offset_t, but this
1126 	 * is exceedingly rare, so we cheat and assume a column width of 10
1127 	 * digits, in order to fit everything cleanly into 80 columns.
1128 	 */
1129 	mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n",
1130 	    addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred,
1131 	    f->f_count);
1132 
1133 	return (WALK_NEXT);
1134 }
1135 
1136 int
1137 pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1138 {
1139 	int opt_f = 0;
1140 
1141 	struct pfiles_cbdata cb;
1142 
1143 	bzero(&cb, sizeof (cb));
1144 
1145 	if (!(flags & DCMD_ADDRSPEC))
1146 		return (DCMD_USAGE);
1147 
1148 	if (mdb_getopts(argc, argv,
1149 	    'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p,
1150 	    'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc)
1151 		return (DCMD_USAGE);
1152 
1153 	if (opt_f) {
1154 		mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE",
1155 		    "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT");
1156 		if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb,
1157 		    addr) == -1) {
1158 			mdb_warn("failed to walk 'allfile'");
1159 			return (DCMD_ERR);
1160 		}
1161 	} else {
1162 		mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE");
1163 		if (cb.opt_p)
1164 			mdb_printf("PATH");
1165 		else
1166 			mdb_printf("INFO");
1167 		mdb_printf("%</u>\n");
1168 
1169 		if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb,
1170 		    addr) == -1) {
1171 			mdb_warn("failed to walk 'allfile'");
1172 			return (DCMD_ERR);
1173 		}
1174 	}
1175 
1176 
1177 	return (DCMD_OK);
1178 }
1179 
1180 void
1181 pfiles_help(void)
1182 {
1183 	mdb_printf(
1184 	    "Given the address of a process, print information about files\n"
1185 	    "which the process has open.  By default, this includes decoded\n"
1186 	    "information about the file depending on file and filesystem type\n"
1187 	    "\n"
1188 	    "\t-p\tPathnames; omit decoded information.  Only display "
1189 	    "pathnames\n"
1190 	    "\t-f\tfile_t view; show the file_t structure corresponding to "
1191 	    "the fd\n");
1192 }
1193