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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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