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 == NULL &&
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 == NULL)
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 = NULL;
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 int 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 == NULL) {
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 }
954
955 do {
956 uintptr_t next_realvpp;
957
958 err = next_realvp(realvpp, &layer_vn, &next_realvpp);
959 if (next_realvpp != NULL)
960 realvpp = next_realvpp;
961
962 } while (err == REALVP_CONTINUE);
963
964 if (err == REALVP_ERR) {
965 mdb_warn("failed to do realvp() for %p", realvpp);
966 return (DCMD_ERR);
967 }
968
969 if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1)
970 return (DCMD_ERR);
971
972 mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep);
973
974 if (cb->opt_p) {
975 if (pfiles_dig_pathname(top_vnodep, path) == -1)
976 return (DCMD_ERR);
977
978 mdb_printf("%s\n", path);
979 return (DCMD_OK);
980 }
981
982 /*
983 * Sockets generally don't have interesting pathnames; we only
984 * show those in the '-p' view.
985 */
986 path[0] = '\0';
987 if (v.v_type != VSOCK) {
988 if (pfiles_dig_pathname(top_vnodep, path) == -1)
989 return (DCMD_ERR);
990 }
991 mdb_printf("%s%s", path, path[0] == '\0' ? "" : " ");
992
993 switch (v.v_type) {
994 case VDOOR:
995 {
996 door_node_t doornode;
997 proc_t pr;
998
999 if (mdb_vread(&doornode, sizeof (doornode),
1000 (uintptr_t)layer_vn.v_data) == -1) {
1001 mdb_warn("failed to read door_node");
1002 return (DCMD_ERR);
1003 }
1004
1005 if (mdb_vread(&pr, sizeof (pr),
1006 (uintptr_t)doornode.door_target) == -1) {
1007 mdb_warn("failed to read door server process %p",
1008 doornode.door_target);
1009 return (DCMD_ERR);
1010 }
1011 mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm,
1012 doornode.door_target);
1013 break;
1014 }
1015
1016 case VSOCK:
1017 {
1018 vnode_t v_sock;
1019 struct sonode so;
1020
1021 if (mdb_vread(&v_sock, sizeof (v_sock), realvpp) == -1) {
1022 mdb_warn("failed to read socket vnode");
1023 return (DCMD_ERR);
1024 }
1025
1026 /*
1027 * Sockets can be non-stream or stream, they have to be dealed
1028 * with differently.
1029 */
1030 if (v_sock.v_stream == NULL) {
1031 if (pfiles_get_sonode(&v_sock, &so) == -1)
1032 return (DCMD_ERR);
1033
1034 /* Pick the proper methods. */
1035 for (i = 0; i <= NUM_SOCK_PRINTS; i++) {
1036 if ((sock_prints[i].family == so.so_family &&
1037 sock_prints[i].type == so.so_type &&
1038 sock_prints[i].pro == so.so_protocol) ||
1039 (sock_prints[i].family == so.so_family &&
1040 sock_prints[i].type == so.so_type &&
1041 so.so_type == SOCK_RAW)) {
1042 if ((*sock_prints[i].print)(&so) == -1)
1043 return (DCMD_ERR);
1044 }
1045 }
1046 } else {
1047 sotpi_sonode_t sotpi_sonode;
1048
1049 if (pfiles_get_sonode(&v_sock, &so) == -1)
1050 return (DCMD_ERR);
1051
1052 /*
1053 * If the socket is a fallback socket, read its related
1054 * information separately; otherwise, read it as a whole
1055 * tpi socket.
1056 */
1057 if (so.so_state & SS_FALLBACK_COMP) {
1058 sotpi_sonode.st_sonode = so;
1059
1060 if (mdb_vread(&(sotpi_sonode.st_info),
1061 sizeof (sotpi_info_t),
1062 (uintptr_t)so.so_priv) == -1)
1063 return (DCMD_ERR);
1064 } else {
1065 if (pfiles_get_tpi_sonode(&v_sock,
1066 &sotpi_sonode) == -1)
1067 return (DCMD_ERR);
1068 }
1069
1070 if (tpi_sock_print(&sotpi_sonode) == -1)
1071 return (DCMD_ERR);
1072 }
1073
1074 break;
1075 }
1076
1077 case VPORT:
1078 mdb_printf("[event port (port=%p)]", v.v_data);
1079 break;
1080
1081 case VPROC:
1082 {
1083 prnode_t prnode;
1084 prcommon_t prcommon;
1085
1086 if (mdb_vread(&prnode, sizeof (prnode),
1087 (uintptr_t)layer_vn.v_data) == -1) {
1088 mdb_warn("failed to read prnode");
1089 return (DCMD_ERR);
1090 }
1091
1092 if (mdb_vread(&prcommon, sizeof (prcommon),
1093 (uintptr_t)prnode.pr_common) == -1) {
1094 mdb_warn("failed to read prcommon %p",
1095 prnode.pr_common);
1096 return (DCMD_ERR);
1097 }
1098
1099 mdb_printf("(proc=%p)", prcommon.prc_proc);
1100 break;
1101 }
1102
1103 default:
1104 break;
1105 }
1106
1107 mdb_printf("\n");
1108
1109 return (WALK_NEXT);
1110 }
1111
1112 static int
file_t_callback(uintptr_t addr,const struct file * f,struct pfiles_cbdata * cb)1113 file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb)
1114 {
1115 int myfd = cb->fd;
1116
1117 cb->fd++;
1118
1119 if (addr == NULL) {
1120 return (WALK_NEXT);
1121 }
1122
1123 /*
1124 * We really need 20 digits to print a 64-bit offset_t, but this
1125 * is exceedingly rare, so we cheat and assume a column width of 10
1126 * digits, in order to fit everything cleanly into 80 columns.
1127 */
1128 mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n",
1129 addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred,
1130 f->f_count);
1131
1132 return (WALK_NEXT);
1133 }
1134
1135 int
pfiles(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1136 pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1137 {
1138 int opt_f = 0;
1139
1140 struct pfiles_cbdata cb;
1141
1142 bzero(&cb, sizeof (cb));
1143
1144 if (!(flags & DCMD_ADDRSPEC))
1145 return (DCMD_USAGE);
1146
1147 if (mdb_getopts(argc, argv,
1148 'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p,
1149 'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc)
1150 return (DCMD_USAGE);
1151
1152 if (opt_f) {
1153 mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE",
1154 "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT");
1155 if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb,
1156 addr) == -1) {
1157 mdb_warn("failed to walk 'allfile'");
1158 return (DCMD_ERR);
1159 }
1160 } else {
1161 mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE");
1162 if (cb.opt_p)
1163 mdb_printf("PATH");
1164 else
1165 mdb_printf("INFO");
1166 mdb_printf("%</u>\n");
1167
1168 if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb,
1169 addr) == -1) {
1170 mdb_warn("failed to walk 'allfile'");
1171 return (DCMD_ERR);
1172 }
1173 }
1174
1175
1176 return (DCMD_OK);
1177 }
1178
1179 void
pfiles_help(void)1180 pfiles_help(void)
1181 {
1182 mdb_printf(
1183 "Given the address of a process, print information about files\n"
1184 "which the process has open. By default, this includes decoded\n"
1185 "information about the file depending on file and filesystem type\n"
1186 "\n"
1187 "\t-p\tPathnames; omit decoded information. Only display "
1188 "pathnames\n"
1189 "\t-f\tfile_t view; show the file_t structure corresponding to "
1190 "the fd\n");
1191 }
1192