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