10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3507Svb160487 * Common Development and Distribution License (the "License"). 6*3507Svb160487 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3507Svb160487 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 290Sstevel@tonic-gate #include <mdb/mdb_ks.h> 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/door.h> 340Sstevel@tonic-gate #include <sys/file.h> 350Sstevel@tonic-gate #include <sys/mount.h> 360Sstevel@tonic-gate #include <sys/proc.h> 370Sstevel@tonic-gate #include <sys/procfs.h> 380Sstevel@tonic-gate #include <sys/proc/prdata.h> 390Sstevel@tonic-gate #include <sys/stat.h> 400Sstevel@tonic-gate #include <sys/vfs.h> 410Sstevel@tonic-gate #include <sys/vnode.h> 420Sstevel@tonic-gate #include <sys/fs/snode.h> 430Sstevel@tonic-gate #include <sys/fs/fifonode.h> 440Sstevel@tonic-gate #include <sys/fs/namenode.h> 450Sstevel@tonic-gate #include <sys/socket.h> 460Sstevel@tonic-gate #include <sys/stropts.h> 470Sstevel@tonic-gate #include <sys/socketvar.h> 480Sstevel@tonic-gate #include <sys/strsubr.h> 490Sstevel@tonic-gate #include <sys/un.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate int 520Sstevel@tonic-gate vfs_walk_init(mdb_walk_state_t *wsp) 530Sstevel@tonic-gate { 540Sstevel@tonic-gate if (wsp->walk_addr == NULL && 550Sstevel@tonic-gate mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) { 560Sstevel@tonic-gate mdb_warn("failed to read 'rootvfs'"); 570Sstevel@tonic-gate return (WALK_ERR); 580Sstevel@tonic-gate } 590Sstevel@tonic-gate 600Sstevel@tonic-gate wsp->walk_data = (void *)wsp->walk_addr; 610Sstevel@tonic-gate return (WALK_NEXT); 620Sstevel@tonic-gate } 630Sstevel@tonic-gate 640Sstevel@tonic-gate int 650Sstevel@tonic-gate vfs_walk_step(mdb_walk_state_t *wsp) 660Sstevel@tonic-gate { 670Sstevel@tonic-gate vfs_t vfs; 680Sstevel@tonic-gate int status; 690Sstevel@tonic-gate 700Sstevel@tonic-gate if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) { 710Sstevel@tonic-gate mdb_warn("failed to read vfs_t at %p", wsp->walk_addr); 720Sstevel@tonic-gate return (WALK_DONE); 730Sstevel@tonic-gate } 740Sstevel@tonic-gate 750Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata); 760Sstevel@tonic-gate 770Sstevel@tonic-gate if (vfs.vfs_next == wsp->walk_data) 780Sstevel@tonic-gate return (WALK_DONE); 790Sstevel@tonic-gate 800Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)vfs.vfs_next; 810Sstevel@tonic-gate 820Sstevel@tonic-gate return (status); 830Sstevel@tonic-gate } 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * Utility routine to read in a filesystem name given a vfs pointer. If 870Sstevel@tonic-gate * no vfssw entry for the vfs is available (as is the case with some pseudo- 880Sstevel@tonic-gate * filesystems), we check against some known problem fs's: doorfs and 890Sstevel@tonic-gate * portfs. If that fails, we try to guess the filesystem name using 900Sstevel@tonic-gate * symbol names. fsname should be a buffer of size _ST_FSTYPSZ. 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate static int 930Sstevel@tonic-gate read_fsname(uintptr_t vfsp, char *fsname) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate vfs_t vfs; 960Sstevel@tonic-gate struct vfssw vfssw_entry; 970Sstevel@tonic-gate GElf_Sym vfssw_sym, test_sym; 980Sstevel@tonic-gate char testname[MDB_SYM_NAMLEN]; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) { 1010Sstevel@tonic-gate mdb_warn("failed to read vfs %p", vfsp); 1020Sstevel@tonic-gate return (-1); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) { 1060Sstevel@tonic-gate mdb_warn("failed to find vfssw"); 1070Sstevel@tonic-gate return (-1); 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * vfssw is an array; we need vfssw[vfs.vfs_fstype]. 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry), 1140Sstevel@tonic-gate vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype)) 1150Sstevel@tonic-gate == -1) { 1160Sstevel@tonic-gate mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype); 1170Sstevel@tonic-gate return (-1); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (vfs.vfs_fstype != 0) { 1210Sstevel@tonic-gate if (mdb_readstr(fsname, _ST_FSTYPSZ, 1220Sstevel@tonic-gate (uintptr_t)vfssw_entry.vsw_name) == -1) { 1230Sstevel@tonic-gate mdb_warn("failed to find fs name %p", 1240Sstevel@tonic-gate vfssw_entry.vsw_name); 1250Sstevel@tonic-gate return (-1); 1260Sstevel@tonic-gate } 1270Sstevel@tonic-gate return (0); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Do precise detection for certain filesystem types that we 1320Sstevel@tonic-gate * know do not appear in vfssw[], and that we depend upon in other 1330Sstevel@tonic-gate * parts of the code: doorfs and portfs. 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) { 1360Sstevel@tonic-gate if (test_sym.st_value == vfsp) { 1370Sstevel@tonic-gate strcpy(fsname, "doorfs"); 1380Sstevel@tonic-gate return (0); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) { 1420Sstevel@tonic-gate if (test_sym.st_value == vfsp) { 1430Sstevel@tonic-gate strcpy(fsname, "portfs"); 1440Sstevel@tonic-gate return (0); 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* 1490Sstevel@tonic-gate * Heuristic detection for other filesystems that don't have a 1500Sstevel@tonic-gate * vfssw[] entry. These tend to be named <fsname>_vfs, so we do a 1510Sstevel@tonic-gate * lookup_by_addr and see if we find a symbol of that name. 1520Sstevel@tonic-gate */ 1530Sstevel@tonic-gate if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname), 1540Sstevel@tonic-gate &test_sym) != -1) { 1550Sstevel@tonic-gate if ((strlen(testname) > 4) && 1560Sstevel@tonic-gate (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) { 1570Sstevel@tonic-gate testname[strlen(testname) - 4] = '\0'; 1580Sstevel@tonic-gate strncpy(fsname, testname, _ST_FSTYPSZ); 1590Sstevel@tonic-gate return (0); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate mdb_warn("unknown filesystem type for vfs %p", vfsp); 1640Sstevel@tonic-gate return (-1); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * Column widths for mount point display in ::fsinfo output. 1690Sstevel@tonic-gate */ 1700Sstevel@tonic-gate #ifdef _LP64 1710Sstevel@tonic-gate #define FSINFO_MNTLEN 48 1720Sstevel@tonic-gate #else 1730Sstevel@tonic-gate #define FSINFO_MNTLEN 56 1740Sstevel@tonic-gate #endif 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /*ARGSUSED*/ 1770Sstevel@tonic-gate int 1780Sstevel@tonic-gate fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate vfs_t vfs; 1810Sstevel@tonic-gate int len; 1820Sstevel@tonic-gate int opt_v = 0; 1830Sstevel@tonic-gate char buf[MAXPATHLEN]; 1840Sstevel@tonic-gate char fsname[_ST_FSTYPSZ]; 1850Sstevel@tonic-gate mntopt_t *mntopts; 1860Sstevel@tonic-gate size_t size; 1870Sstevel@tonic-gate int i; 1880Sstevel@tonic-gate int first = 1; 1890Sstevel@tonic-gate char opt[MAX_MNTOPT_STR]; 1900Sstevel@tonic-gate uintptr_t global_zone; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 1930Sstevel@tonic-gate if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) { 1940Sstevel@tonic-gate mdb_warn("failed to walk file system list"); 1950Sstevel@tonic-gate return (DCMD_ERR); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate return (DCMD_OK); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate if (mdb_getopts(argc, argv, 2010Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 2020Sstevel@tonic-gate return (DCMD_USAGE); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) 2050Sstevel@tonic-gate mdb_printf("%<u>%?s %-15s %s%</u>\n", 2060Sstevel@tonic-gate "VFSP", "FS", "MOUNT"); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) { 2090Sstevel@tonic-gate mdb_warn("failed to read vfs_t %p", addr); 2100Sstevel@tonic-gate return (DCMD_ERR); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf, 2140Sstevel@tonic-gate sizeof (buf))) <= 0) 2150Sstevel@tonic-gate strcpy(buf, "??"); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate else if (!opt_v && (len >= FSINFO_MNTLEN)) 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * In normal mode, we truncate the path to keep the output 2200Sstevel@tonic-gate * clean. In -v mode, we just print the full path. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate strcpy(&buf[FSINFO_MNTLEN - 4], "..."); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate if (read_fsname(addr, fsname) == -1) 2250Sstevel@tonic-gate return (DCMD_ERR); 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate mdb_printf("%0?p %-15s %s\n", addr, fsname, buf); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate if (!opt_v) 2300Sstevel@tonic-gate return (DCMD_OK); 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * Print 'resource' string; this shows what we're mounted upon. 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf, 2360Sstevel@tonic-gate MAXPATHLEN) <= 0) 2370Sstevel@tonic-gate strcpy(buf, "??"); 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate mdb_printf("%?s %s\n", "R:", buf); 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * Print mount options array; it sucks to be a mimic, but we copy 2430Sstevel@tonic-gate * the same logic as in mntvnops.c for adding zone= tags, and we 2440Sstevel@tonic-gate * don't bother with the obsolete dev= option. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t); 2470Sstevel@tonic-gate mntopts = mdb_alloc(size, UM_SLEEP | UM_GC); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (mdb_vread(mntopts, size, 2500Sstevel@tonic-gate (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) { 2510Sstevel@tonic-gate mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list); 2520Sstevel@tonic-gate return (DCMD_ERR); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) { 2560Sstevel@tonic-gate if (mntopts[i].mo_flags & MO_SET) { 2570Sstevel@tonic-gate if (mdb_readstr(opt, sizeof (opt), 2580Sstevel@tonic-gate (uintptr_t)mntopts[i].mo_name) == -1) { 2590Sstevel@tonic-gate mdb_warn("failed to read mntopt name %p", 2600Sstevel@tonic-gate mntopts[i].mo_name); 2610Sstevel@tonic-gate return (DCMD_ERR); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate if (first) { 2640Sstevel@tonic-gate mdb_printf("%?s ", "O:"); 2650Sstevel@tonic-gate first = 0; 2660Sstevel@tonic-gate } else { 2670Sstevel@tonic-gate mdb_printf(","); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate mdb_printf("%s", opt); 2700Sstevel@tonic-gate if (mntopts[i].mo_flags & MO_HASVALUE) { 2710Sstevel@tonic-gate if (mdb_readstr(opt, sizeof (opt), 2720Sstevel@tonic-gate (uintptr_t)mntopts[i].mo_arg) == -1) { 2730Sstevel@tonic-gate mdb_warn("failed to read mntopt " 2740Sstevel@tonic-gate "value %p", mntopts[i].mo_arg); 2750Sstevel@tonic-gate return (DCMD_ERR); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate mdb_printf("=%s", opt); 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate if (mdb_readvar(&global_zone, "global_zone") == -1) { 2830Sstevel@tonic-gate mdb_warn("failed to locate global_zone"); 2840Sstevel@tonic-gate return (DCMD_ERR); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate if ((vfs.vfs_zone != NULL) && 2880Sstevel@tonic-gate ((uintptr_t)vfs.vfs_zone != global_zone)) { 2890Sstevel@tonic-gate zone_t z; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) { 2920Sstevel@tonic-gate mdb_warn("failed to read zone"); 2930Sstevel@tonic-gate return (DCMD_ERR); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * zone names are much shorter than MAX_MNTOPT_STR 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate if (mdb_readstr(opt, sizeof (opt), 2990Sstevel@tonic-gate (uintptr_t)z.zone_name) == -1) { 3000Sstevel@tonic-gate mdb_warn("failed to read zone name"); 3010Sstevel@tonic-gate return (DCMD_ERR); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate if (first) { 3040Sstevel@tonic-gate mdb_printf("%?s ", "O:"); 3050Sstevel@tonic-gate } else { 3060Sstevel@tonic-gate mdb_printf(","); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate mdb_printf("zone=%s", opt); 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate return (DCMD_OK); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate #define REALVP_DONE 0 3150Sstevel@tonic-gate #define REALVP_ERR 1 3160Sstevel@tonic-gate #define REALVP_CONTINUE 2 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate static int 3190Sstevel@tonic-gate next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp) 3200Sstevel@tonic-gate { 3210Sstevel@tonic-gate char fsname[_ST_FSTYPSZ]; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate *outvp = invp; 3240Sstevel@tonic-gate if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) { 3250Sstevel@tonic-gate mdb_warn("failed to read vnode at %p", invp); 3260Sstevel@tonic-gate return (REALVP_ERR); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1) 3300Sstevel@tonic-gate return (REALVP_ERR); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * We know how to do 'realvp' for as many filesystems as possible; 3340Sstevel@tonic-gate * for all other filesystems, we assume that the vp we are given 3350Sstevel@tonic-gate * is the realvp. In the kernel, a realvp operation will sometimes 3360Sstevel@tonic-gate * dig through multiple layers. Here, we only fetch the pointer 3370Sstevel@tonic-gate * to the next layer down. This allows dcmds to print out the 3380Sstevel@tonic-gate * various layers. 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate if (strcmp(fsname, "fifofs") == 0) { 3410Sstevel@tonic-gate fifonode_t fn; 3420Sstevel@tonic-gate if (mdb_vread(&fn, sizeof (fn), 3430Sstevel@tonic-gate (uintptr_t)outvn->v_data) == -1) { 3440Sstevel@tonic-gate mdb_warn("failed to read fifonode"); 3450Sstevel@tonic-gate return (REALVP_ERR); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate *outvp = (uintptr_t)fn.fn_realvp; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate } else if (strcmp(fsname, "namefs") == 0) { 3500Sstevel@tonic-gate struct namenode nn; 3510Sstevel@tonic-gate if (mdb_vread(&nn, sizeof (nn), 3520Sstevel@tonic-gate (uintptr_t)outvn->v_data) == -1) { 3530Sstevel@tonic-gate mdb_warn("failed to read namenode"); 3540Sstevel@tonic-gate return (REALVP_ERR); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate *outvp = (uintptr_t)nn.nm_filevp; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate } else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) { 3590Sstevel@tonic-gate struct stdata stream; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate /* 3620Sstevel@tonic-gate * Sockets have a strange and different layering scheme; we 3630Sstevel@tonic-gate * hop over into the sockfs vnode (accessible via the stream 3640Sstevel@tonic-gate * head) if possible. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate if (mdb_vread(&stream, sizeof (stream), 3670Sstevel@tonic-gate (uintptr_t)outvn->v_stream) == -1) { 3680Sstevel@tonic-gate mdb_warn("failed to read stream data"); 3690Sstevel@tonic-gate return (REALVP_ERR); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate *outvp = (uintptr_t)stream.sd_vnode; 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (*outvp == invp || *outvp == NULL) 3750Sstevel@tonic-gate return (REALVP_DONE); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate return (REALVP_CONTINUE); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate static void 3810Sstevel@tonic-gate pfiles_print_addr(struct sockaddr *addr) 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate struct sockaddr_in *s_in; 3840Sstevel@tonic-gate struct sockaddr_un *s_un; 3850Sstevel@tonic-gate struct sockaddr_in6 *s_in6; 386*3507Svb160487 in_port_t port; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate switch (addr->sa_family) { 3890Sstevel@tonic-gate case AF_INET: 3900Sstevel@tonic-gate /*LINTED: alignment*/ 3910Sstevel@tonic-gate s_in = (struct sockaddr_in *)addr; 392*3507Svb160487 mdb_nhconvert(&port, &s_in->sin_port, sizeof (port)); 393*3507Svb160487 mdb_printf("AF_INET %I %d ", s_in->sin_addr.s_addr, port); 3940Sstevel@tonic-gate break; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate case AF_INET6: 3970Sstevel@tonic-gate /*LINTED: alignment*/ 3980Sstevel@tonic-gate s_in6 = (struct sockaddr_in6 *)addr; 399*3507Svb160487 mdb_nhconvert(&port, &s_in6->sin6_port, sizeof (port)); 400*3507Svb160487 mdb_printf("AF_INET6 %N %d ", &(s_in6->sin6_addr), port); 4010Sstevel@tonic-gate break; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate case AF_UNIX: 4040Sstevel@tonic-gate s_un = (struct sockaddr_un *)addr; 4050Sstevel@tonic-gate mdb_printf("AF_UNIX %s ", s_un->sun_path); 4060Sstevel@tonic-gate break; 4070Sstevel@tonic-gate default: 4080Sstevel@tonic-gate mdb_printf("AF_?? (%d) ", addr->sa_family); 4090Sstevel@tonic-gate break; 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate static int 4150Sstevel@tonic-gate pfiles_get_sonode(uintptr_t vp, struct sonode *sonode) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate vnode_t v; 4180Sstevel@tonic-gate struct stdata stream; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), vp) == -1) { 4210Sstevel@tonic-gate mdb_warn("failed to read socket vnode"); 4220Sstevel@tonic-gate return (-1); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (mdb_vread(&stream, sizeof (stream), (uintptr_t)v.v_stream) == -1) { 4260Sstevel@tonic-gate mdb_warn("failed to read stream data"); 4270Sstevel@tonic-gate return (-1); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), (uintptr_t)stream.sd_vnode) == -1) { 4310Sstevel@tonic-gate mdb_warn("failed to read stream vnode"); 4320Sstevel@tonic-gate return (-1); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (mdb_vread(sonode, sizeof (struct sonode), 4360Sstevel@tonic-gate (uintptr_t)v.v_data) == -1) { 4370Sstevel@tonic-gate mdb_warn("failed to read sonode"); 4380Sstevel@tonic-gate return (-1); 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate return (0); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate /* 4450Sstevel@tonic-gate * Do some digging to get a reasonable pathname for this vnode. 'path' 4460Sstevel@tonic-gate * should point at a buffer of MAXPATHLEN in size. 4470Sstevel@tonic-gate */ 4480Sstevel@tonic-gate static int 4490Sstevel@tonic-gate pfiles_dig_pathname(uintptr_t vp, char *path) 4500Sstevel@tonic-gate { 4510Sstevel@tonic-gate vnode_t v; 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate bzero(path, MAXPATHLEN); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), vp) == -1) { 4560Sstevel@tonic-gate mdb_warn("failed to read vnode"); 4570Sstevel@tonic-gate return (-1); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate if (v.v_path == NULL) { 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * fifo's and doors are special. Some have pathnames, and 4630Sstevel@tonic-gate * some do not. And for these, it is pointless to go off to 4640Sstevel@tonic-gate * mdb_vnode2path, which is very slow. 4650Sstevel@tonic-gate * 4660Sstevel@tonic-gate * Event ports never have a pathname. 4670Sstevel@tonic-gate */ 4680Sstevel@tonic-gate if (v.v_type == VFIFO || v.v_type == VDOOR || v.v_type == VPORT) 4690Sstevel@tonic-gate return (0); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * For sockets, we won't find a path unless we print the path 4730Sstevel@tonic-gate * associated with the accessvp. 4740Sstevel@tonic-gate */ 4750Sstevel@tonic-gate if (v.v_type == VSOCK) { 4760Sstevel@tonic-gate struct sonode sonode; 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate if (pfiles_get_sonode(vp, &sonode) == -1) { 4790Sstevel@tonic-gate return (-1); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate vp = (uintptr_t)sonode.so_accessvp; 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* 4880Sstevel@tonic-gate * mdb_vnode2path will print an error for us as needed, but not 4890Sstevel@tonic-gate * finding a pathname is not really an error, so we plow on. 4900Sstevel@tonic-gate */ 4910Sstevel@tonic-gate (void) mdb_vnode2path(vp, path, MAXPATHLEN); 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * A common problem is that device pathnames are prefixed with 4950Sstevel@tonic-gate * /dev/../devices/. We just clean those up slightly: 4960Sstevel@tonic-gate * /dev/../devices/<mumble> --> /devices/<mumble> 4970Sstevel@tonic-gate * /dev/pts/../../devices/<mumble> --> /devices/<mumble> 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate if (strncmp("/dev/../devices/", path, strlen("/dev/../devices/")) == 0) 5000Sstevel@tonic-gate strcpy(path, path + 7); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate if (strncmp("/dev/pts/../../devices/", path, 5030Sstevel@tonic-gate strlen("/dev/pts/../../devices/")) == 0) 5040Sstevel@tonic-gate strcpy(path, path + 14); 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate return (0); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate const struct fs_type { 5100Sstevel@tonic-gate int type; 5110Sstevel@tonic-gate const char *name; 5120Sstevel@tonic-gate } fs_types[] = { 5130Sstevel@tonic-gate { VNON, "NON" }, 5140Sstevel@tonic-gate { VREG, "REG" }, 5150Sstevel@tonic-gate { VDIR, "DIR" }, 5160Sstevel@tonic-gate { VBLK, "BLK" }, 5170Sstevel@tonic-gate { VCHR, "CHR" }, 5180Sstevel@tonic-gate { VLNK, "LNK" }, 5190Sstevel@tonic-gate { VFIFO, "FIFO" }, 5200Sstevel@tonic-gate { VDOOR, "DOOR" }, 5210Sstevel@tonic-gate { VPROC, "PROC" }, 5220Sstevel@tonic-gate { VSOCK, "SOCK" }, 5230Sstevel@tonic-gate { VPORT, "PORT" }, 5240Sstevel@tonic-gate { VBAD, "BAD" } 5250Sstevel@tonic-gate }; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate #define NUM_FS_TYPES (sizeof (fs_types) / sizeof (struct fs_type)) 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate struct pfiles_cbdata { 5300Sstevel@tonic-gate int opt_p; 5310Sstevel@tonic-gate int fd; 5320Sstevel@tonic-gate }; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate static int 5350Sstevel@tonic-gate pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb) 5360Sstevel@tonic-gate { 5370Sstevel@tonic-gate vnode_t v, layer_vn; 5380Sstevel@tonic-gate int myfd = cb->fd; 5390Sstevel@tonic-gate const char *type; 5400Sstevel@tonic-gate char path[MAXPATHLEN]; 5410Sstevel@tonic-gate uintptr_t top_vnodep, realvpp; 5420Sstevel@tonic-gate char fsname[_ST_FSTYPSZ]; 5430Sstevel@tonic-gate int err, i; 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate cb->fd++; 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate if (addr == NULL) { 5480Sstevel@tonic-gate return (WALK_NEXT); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate top_vnodep = realvpp = (uintptr_t)f->f_vnode; 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), realvpp) == -1) { 5540Sstevel@tonic-gate mdb_warn("failed to read vnode"); 5550Sstevel@tonic-gate return (DCMD_ERR); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate type = "?"; 5590Sstevel@tonic-gate for (i = 0; i <= NUM_FS_TYPES; i++) { 5600Sstevel@tonic-gate if (fs_types[i].type == v.v_type) 5610Sstevel@tonic-gate type = fs_types[i].name; 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate do { 5650Sstevel@tonic-gate uintptr_t next_realvpp; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate err = next_realvp(realvpp, &layer_vn, &next_realvpp); 5680Sstevel@tonic-gate if (next_realvpp != NULL) 5690Sstevel@tonic-gate realvpp = next_realvpp; 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate } while (err == REALVP_CONTINUE); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate if (err == REALVP_ERR) { 5740Sstevel@tonic-gate mdb_warn("failed to do realvp() for %p", realvpp); 5750Sstevel@tonic-gate return (DCMD_ERR); 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1) 5790Sstevel@tonic-gate return (DCMD_ERR); 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (cb->opt_p) { 5840Sstevel@tonic-gate if (pfiles_dig_pathname(top_vnodep, path) == -1) 5850Sstevel@tonic-gate return (DCMD_ERR); 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate mdb_printf("%s\n", path); 5880Sstevel@tonic-gate return (DCMD_OK); 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate /* 5920Sstevel@tonic-gate * Sockets generally don't have interesting pathnames; we only 5930Sstevel@tonic-gate * show those in the '-p' view. 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate path[0] = '\0'; 5960Sstevel@tonic-gate if (v.v_type != VSOCK) { 5970Sstevel@tonic-gate if (pfiles_dig_pathname(top_vnodep, path) == -1) 5980Sstevel@tonic-gate return (DCMD_ERR); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate mdb_printf("%s%s", path, path[0] == '\0' ? "" : " "); 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate switch (v.v_type) { 6030Sstevel@tonic-gate case VDOOR: 6040Sstevel@tonic-gate { 6050Sstevel@tonic-gate door_node_t doornode; 6060Sstevel@tonic-gate proc_t pr; 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (mdb_vread(&doornode, sizeof (doornode), 6090Sstevel@tonic-gate (uintptr_t)layer_vn.v_data) == -1) { 6100Sstevel@tonic-gate mdb_warn("failed to read door_node"); 6110Sstevel@tonic-gate return (DCMD_ERR); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if (mdb_vread(&pr, sizeof (pr), 6150Sstevel@tonic-gate (uintptr_t)doornode.door_target) == -1) { 6160Sstevel@tonic-gate mdb_warn("failed to read door server process %p", 6170Sstevel@tonic-gate doornode.door_target); 6180Sstevel@tonic-gate return (DCMD_ERR); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm, 6210Sstevel@tonic-gate doornode.door_target); 6220Sstevel@tonic-gate break; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate case VSOCK: 6260Sstevel@tonic-gate { 6270Sstevel@tonic-gate struct sonode sonode; 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if (pfiles_get_sonode(realvpp, &sonode) == -1) 6300Sstevel@tonic-gate return (DCMD_ERR); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* 6330Sstevel@tonic-gate * If the address is cached in the sonode, use it; otherwise, 6340Sstevel@tonic-gate * we print nothing. 6350Sstevel@tonic-gate */ 6360Sstevel@tonic-gate if (sonode.so_state & SS_LADDR_VALID) { 6370Sstevel@tonic-gate struct sockaddr *laddr = 6380Sstevel@tonic-gate mdb_alloc(sonode.so_laddr_len, UM_SLEEP); 6390Sstevel@tonic-gate if (mdb_vread(laddr, sonode.so_laddr_len, 6400Sstevel@tonic-gate (uintptr_t)sonode.so_laddr_sa) == -1) { 6410Sstevel@tonic-gate mdb_warn("failed to read sonode socket addr"); 6420Sstevel@tonic-gate return (DCMD_ERR); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate mdb_printf("socket: "); 6460Sstevel@tonic-gate pfiles_print_addr(laddr); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if (sonode.so_state & SS_FADDR_VALID) { 6500Sstevel@tonic-gate struct sockaddr *faddr = 6510Sstevel@tonic-gate mdb_alloc(sonode.so_faddr_len, UM_SLEEP); 6520Sstevel@tonic-gate if (mdb_vread(faddr, sonode.so_faddr_len, 6530Sstevel@tonic-gate (uintptr_t)sonode.so_faddr_sa) == -1) { 6540Sstevel@tonic-gate mdb_warn("failed to read sonode remote addr"); 6550Sstevel@tonic-gate return (DCMD_ERR); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate mdb_printf("remote: "); 6590Sstevel@tonic-gate pfiles_print_addr(faddr); 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate break; 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate case VPORT: 6650Sstevel@tonic-gate mdb_printf("[event port (port=%p)]", v.v_data); 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate case VPROC: 6690Sstevel@tonic-gate { 6700Sstevel@tonic-gate prnode_t prnode; 6710Sstevel@tonic-gate prcommon_t prcommon; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate if (mdb_vread(&prnode, sizeof (prnode), 6740Sstevel@tonic-gate (uintptr_t)layer_vn.v_data) == -1) { 6750Sstevel@tonic-gate mdb_warn("failed to read prnode"); 6760Sstevel@tonic-gate return (DCMD_ERR); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (mdb_vread(&prcommon, sizeof (prcommon), 6800Sstevel@tonic-gate (uintptr_t)prnode.pr_common) == -1) { 6810Sstevel@tonic-gate mdb_warn("failed to read prcommon %p", 6820Sstevel@tonic-gate prnode.pr_common); 6830Sstevel@tonic-gate return (DCMD_ERR); 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate mdb_printf("(proc=%p)", prcommon.prc_proc); 6870Sstevel@tonic-gate break; 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate default: 6910Sstevel@tonic-gate break; 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate mdb_printf("\n"); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate return (WALK_NEXT); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate static int 7010Sstevel@tonic-gate file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb) 7020Sstevel@tonic-gate { 7030Sstevel@tonic-gate int myfd = cb->fd; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate cb->fd++; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate if (addr == NULL) { 7080Sstevel@tonic-gate return (WALK_NEXT); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate /* 7120Sstevel@tonic-gate * We really need 20 digits to print a 64-bit offset_t, but this 7130Sstevel@tonic-gate * is exceedingly rare, so we cheat and assume a column width of 10 7140Sstevel@tonic-gate * digits, in order to fit everything cleanly into 80 columns. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n", 7170Sstevel@tonic-gate addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred, 7180Sstevel@tonic-gate f->f_count); 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate return (WALK_NEXT); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate int 7240Sstevel@tonic-gate pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 7250Sstevel@tonic-gate { 7260Sstevel@tonic-gate int opt_f = 0; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate struct pfiles_cbdata cb; 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate bzero(&cb, sizeof (cb)); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 7330Sstevel@tonic-gate return (DCMD_USAGE); 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate if (mdb_getopts(argc, argv, 7360Sstevel@tonic-gate 'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p, 7370Sstevel@tonic-gate 'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc) 7380Sstevel@tonic-gate return (DCMD_USAGE); 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate if (opt_f) { 7410Sstevel@tonic-gate mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE", 7420Sstevel@tonic-gate "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT"); 7430Sstevel@tonic-gate if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb, 7440Sstevel@tonic-gate addr) == -1) { 7450Sstevel@tonic-gate mdb_warn("failed to walk 'allfile'"); 7460Sstevel@tonic-gate return (DCMD_ERR); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate } else { 7490Sstevel@tonic-gate mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE"); 7500Sstevel@tonic-gate if (cb.opt_p) 7510Sstevel@tonic-gate mdb_printf("PATH"); 7520Sstevel@tonic-gate else 7530Sstevel@tonic-gate mdb_printf("INFO"); 7540Sstevel@tonic-gate mdb_printf("%</u>\n"); 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb, 7570Sstevel@tonic-gate addr) == -1) { 7580Sstevel@tonic-gate mdb_warn("failed to walk 'allfile'"); 7590Sstevel@tonic-gate return (DCMD_ERR); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate return (DCMD_OK); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate void 7680Sstevel@tonic-gate pfiles_help(void) 7690Sstevel@tonic-gate { 7700Sstevel@tonic-gate mdb_printf( 7710Sstevel@tonic-gate "Given the address of a process, print information about files\n" 7720Sstevel@tonic-gate "which the process has open. By default, this includes decoded\n" 7730Sstevel@tonic-gate "information about the file depending on file and filesystem type\n" 7740Sstevel@tonic-gate "\n" 7750Sstevel@tonic-gate "\t-p\tPathnames; omit decoded information. Only display " 7760Sstevel@tonic-gate "pathnames\n" 7770Sstevel@tonic-gate "\t-f\tfile_t view; show the file_t structure corresponding to " 7780Sstevel@tonic-gate "the fd\n"); 7790Sstevel@tonic-gate } 780