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