1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 30*0Sstevel@tonic-gate #include <mdb/mdb_ks.h> 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <sys/types.h> 33*0Sstevel@tonic-gate #include <sys/systm.h> 34*0Sstevel@tonic-gate #include <sys/door.h> 35*0Sstevel@tonic-gate #include <sys/file.h> 36*0Sstevel@tonic-gate #include <sys/mount.h> 37*0Sstevel@tonic-gate #include <sys/proc.h> 38*0Sstevel@tonic-gate #include <sys/procfs.h> 39*0Sstevel@tonic-gate #include <sys/proc/prdata.h> 40*0Sstevel@tonic-gate #include <sys/stat.h> 41*0Sstevel@tonic-gate #include <sys/vfs.h> 42*0Sstevel@tonic-gate #include <sys/vnode.h> 43*0Sstevel@tonic-gate #include <sys/fs/snode.h> 44*0Sstevel@tonic-gate #include <sys/fs/fifonode.h> 45*0Sstevel@tonic-gate #include <sys/fs/namenode.h> 46*0Sstevel@tonic-gate #include <sys/socket.h> 47*0Sstevel@tonic-gate #include <sys/stropts.h> 48*0Sstevel@tonic-gate #include <sys/socketvar.h> 49*0Sstevel@tonic-gate #include <sys/strsubr.h> 50*0Sstevel@tonic-gate #include <sys/un.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate int 53*0Sstevel@tonic-gate vfs_walk_init(mdb_walk_state_t *wsp) 54*0Sstevel@tonic-gate { 55*0Sstevel@tonic-gate if (wsp->walk_addr == NULL && 56*0Sstevel@tonic-gate mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) { 57*0Sstevel@tonic-gate mdb_warn("failed to read 'rootvfs'"); 58*0Sstevel@tonic-gate return (WALK_ERR); 59*0Sstevel@tonic-gate } 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate wsp->walk_data = (void *)wsp->walk_addr; 62*0Sstevel@tonic-gate return (WALK_NEXT); 63*0Sstevel@tonic-gate } 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate int 66*0Sstevel@tonic-gate vfs_walk_step(mdb_walk_state_t *wsp) 67*0Sstevel@tonic-gate { 68*0Sstevel@tonic-gate vfs_t vfs; 69*0Sstevel@tonic-gate int status; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) { 72*0Sstevel@tonic-gate mdb_warn("failed to read vfs_t at %p", wsp->walk_addr); 73*0Sstevel@tonic-gate return (WALK_DONE); 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate if (vfs.vfs_next == wsp->walk_data) 79*0Sstevel@tonic-gate return (WALK_DONE); 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)vfs.vfs_next; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate return (status); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * Utility routine to read in a filesystem name given a vfs pointer. If 88*0Sstevel@tonic-gate * no vfssw entry for the vfs is available (as is the case with some pseudo- 89*0Sstevel@tonic-gate * filesystems), we check against some known problem fs's: doorfs and 90*0Sstevel@tonic-gate * portfs. If that fails, we try to guess the filesystem name using 91*0Sstevel@tonic-gate * symbol names. fsname should be a buffer of size _ST_FSTYPSZ. 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate static int 94*0Sstevel@tonic-gate read_fsname(uintptr_t vfsp, char *fsname) 95*0Sstevel@tonic-gate { 96*0Sstevel@tonic-gate vfs_t vfs; 97*0Sstevel@tonic-gate struct vfssw vfssw_entry; 98*0Sstevel@tonic-gate GElf_Sym vfssw_sym, test_sym; 99*0Sstevel@tonic-gate char testname[MDB_SYM_NAMLEN]; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) { 102*0Sstevel@tonic-gate mdb_warn("failed to read vfs %p", vfsp); 103*0Sstevel@tonic-gate return (-1); 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) { 107*0Sstevel@tonic-gate mdb_warn("failed to find vfssw"); 108*0Sstevel@tonic-gate return (-1); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate /* 112*0Sstevel@tonic-gate * vfssw is an array; we need vfssw[vfs.vfs_fstype]. 113*0Sstevel@tonic-gate */ 114*0Sstevel@tonic-gate if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry), 115*0Sstevel@tonic-gate vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype)) 116*0Sstevel@tonic-gate == -1) { 117*0Sstevel@tonic-gate mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype); 118*0Sstevel@tonic-gate return (-1); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate if (vfs.vfs_fstype != 0) { 122*0Sstevel@tonic-gate if (mdb_readstr(fsname, _ST_FSTYPSZ, 123*0Sstevel@tonic-gate (uintptr_t)vfssw_entry.vsw_name) == -1) { 124*0Sstevel@tonic-gate mdb_warn("failed to find fs name %p", 125*0Sstevel@tonic-gate vfssw_entry.vsw_name); 126*0Sstevel@tonic-gate return (-1); 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate return (0); 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate /* 132*0Sstevel@tonic-gate * Do precise detection for certain filesystem types that we 133*0Sstevel@tonic-gate * know do not appear in vfssw[], and that we depend upon in other 134*0Sstevel@tonic-gate * parts of the code: doorfs and portfs. 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) { 137*0Sstevel@tonic-gate if (test_sym.st_value == vfsp) { 138*0Sstevel@tonic-gate strcpy(fsname, "doorfs"); 139*0Sstevel@tonic-gate return (0); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) { 143*0Sstevel@tonic-gate if (test_sym.st_value == vfsp) { 144*0Sstevel@tonic-gate strcpy(fsname, "portfs"); 145*0Sstevel@tonic-gate return (0); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Heuristic detection for other filesystems that don't have a 151*0Sstevel@tonic-gate * vfssw[] entry. These tend to be named <fsname>_vfs, so we do a 152*0Sstevel@tonic-gate * lookup_by_addr and see if we find a symbol of that name. 153*0Sstevel@tonic-gate */ 154*0Sstevel@tonic-gate if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname), 155*0Sstevel@tonic-gate &test_sym) != -1) { 156*0Sstevel@tonic-gate if ((strlen(testname) > 4) && 157*0Sstevel@tonic-gate (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) { 158*0Sstevel@tonic-gate testname[strlen(testname) - 4] = '\0'; 159*0Sstevel@tonic-gate strncpy(fsname, testname, _ST_FSTYPSZ); 160*0Sstevel@tonic-gate return (0); 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate mdb_warn("unknown filesystem type for vfs %p", vfsp); 165*0Sstevel@tonic-gate return (-1); 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * Column widths for mount point display in ::fsinfo output. 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate #ifdef _LP64 172*0Sstevel@tonic-gate #define FSINFO_MNTLEN 48 173*0Sstevel@tonic-gate #else 174*0Sstevel@tonic-gate #define FSINFO_MNTLEN 56 175*0Sstevel@tonic-gate #endif 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate /*ARGSUSED*/ 178*0Sstevel@tonic-gate int 179*0Sstevel@tonic-gate fsinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 180*0Sstevel@tonic-gate { 181*0Sstevel@tonic-gate vfs_t vfs; 182*0Sstevel@tonic-gate int len; 183*0Sstevel@tonic-gate int opt_v = 0; 184*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 185*0Sstevel@tonic-gate char fsname[_ST_FSTYPSZ]; 186*0Sstevel@tonic-gate mntopt_t *mntopts; 187*0Sstevel@tonic-gate size_t size; 188*0Sstevel@tonic-gate int i; 189*0Sstevel@tonic-gate int first = 1; 190*0Sstevel@tonic-gate char opt[MAX_MNTOPT_STR]; 191*0Sstevel@tonic-gate uintptr_t global_zone; 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 194*0Sstevel@tonic-gate if (mdb_walk_dcmd("vfs", "fsinfo", argc, argv) == -1) { 195*0Sstevel@tonic-gate mdb_warn("failed to walk file system list"); 196*0Sstevel@tonic-gate return (DCMD_ERR); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate return (DCMD_OK); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate if (mdb_getopts(argc, argv, 202*0Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 203*0Sstevel@tonic-gate return (DCMD_USAGE); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) 206*0Sstevel@tonic-gate mdb_printf("%<u>%?s %-15s %s%</u>\n", 207*0Sstevel@tonic-gate "VFSP", "FS", "MOUNT"); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate if (mdb_vread(&vfs, sizeof (vfs), addr) == -1) { 210*0Sstevel@tonic-gate mdb_warn("failed to read vfs_t %p", addr); 211*0Sstevel@tonic-gate return (DCMD_ERR); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate if ((len = mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf, 215*0Sstevel@tonic-gate sizeof (buf))) <= 0) 216*0Sstevel@tonic-gate strcpy(buf, "??"); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate else if (!opt_v && (len >= FSINFO_MNTLEN)) 219*0Sstevel@tonic-gate /* 220*0Sstevel@tonic-gate * In normal mode, we truncate the path to keep the output 221*0Sstevel@tonic-gate * clean. In -v mode, we just print the full path. 222*0Sstevel@tonic-gate */ 223*0Sstevel@tonic-gate strcpy(&buf[FSINFO_MNTLEN - 4], "..."); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (read_fsname(addr, fsname) == -1) 226*0Sstevel@tonic-gate return (DCMD_ERR); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate mdb_printf("%0?p %-15s %s\n", addr, fsname, buf); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if (!opt_v) 231*0Sstevel@tonic-gate return (DCMD_OK); 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * Print 'resource' string; this shows what we're mounted upon. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf, 237*0Sstevel@tonic-gate MAXPATHLEN) <= 0) 238*0Sstevel@tonic-gate strcpy(buf, "??"); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate mdb_printf("%?s %s\n", "R:", buf); 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * Print mount options array; it sucks to be a mimic, but we copy 244*0Sstevel@tonic-gate * the same logic as in mntvnops.c for adding zone= tags, and we 245*0Sstevel@tonic-gate * don't bother with the obsolete dev= option. 246*0Sstevel@tonic-gate */ 247*0Sstevel@tonic-gate size = vfs.vfs_mntopts.mo_count * sizeof (mntopt_t); 248*0Sstevel@tonic-gate mntopts = mdb_alloc(size, UM_SLEEP | UM_GC); 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (mdb_vread(mntopts, size, 251*0Sstevel@tonic-gate (uintptr_t)vfs.vfs_mntopts.mo_list) == -1) { 252*0Sstevel@tonic-gate mdb_warn("failed to read mntopts %p", vfs.vfs_mntopts.mo_list); 253*0Sstevel@tonic-gate return (DCMD_ERR); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate for (i = 0; i < vfs.vfs_mntopts.mo_count; i++) { 257*0Sstevel@tonic-gate if (mntopts[i].mo_flags & MO_SET) { 258*0Sstevel@tonic-gate if (mdb_readstr(opt, sizeof (opt), 259*0Sstevel@tonic-gate (uintptr_t)mntopts[i].mo_name) == -1) { 260*0Sstevel@tonic-gate mdb_warn("failed to read mntopt name %p", 261*0Sstevel@tonic-gate mntopts[i].mo_name); 262*0Sstevel@tonic-gate return (DCMD_ERR); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate if (first) { 265*0Sstevel@tonic-gate mdb_printf("%?s ", "O:"); 266*0Sstevel@tonic-gate first = 0; 267*0Sstevel@tonic-gate } else { 268*0Sstevel@tonic-gate mdb_printf(","); 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate mdb_printf("%s", opt); 271*0Sstevel@tonic-gate if (mntopts[i].mo_flags & MO_HASVALUE) { 272*0Sstevel@tonic-gate if (mdb_readstr(opt, sizeof (opt), 273*0Sstevel@tonic-gate (uintptr_t)mntopts[i].mo_arg) == -1) { 274*0Sstevel@tonic-gate mdb_warn("failed to read mntopt " 275*0Sstevel@tonic-gate "value %p", mntopts[i].mo_arg); 276*0Sstevel@tonic-gate return (DCMD_ERR); 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate mdb_printf("=%s", opt); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if (mdb_readvar(&global_zone, "global_zone") == -1) { 284*0Sstevel@tonic-gate mdb_warn("failed to locate global_zone"); 285*0Sstevel@tonic-gate return (DCMD_ERR); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if ((vfs.vfs_zone != NULL) && 289*0Sstevel@tonic-gate ((uintptr_t)vfs.vfs_zone != global_zone)) { 290*0Sstevel@tonic-gate zone_t z; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if (mdb_vread(&z, sizeof (z), (uintptr_t)vfs.vfs_zone) == -1) { 293*0Sstevel@tonic-gate mdb_warn("failed to read zone"); 294*0Sstevel@tonic-gate return (DCMD_ERR); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate /* 297*0Sstevel@tonic-gate * zone names are much shorter than MAX_MNTOPT_STR 298*0Sstevel@tonic-gate */ 299*0Sstevel@tonic-gate if (mdb_readstr(opt, sizeof (opt), 300*0Sstevel@tonic-gate (uintptr_t)z.zone_name) == -1) { 301*0Sstevel@tonic-gate mdb_warn("failed to read zone name"); 302*0Sstevel@tonic-gate return (DCMD_ERR); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate if (first) { 305*0Sstevel@tonic-gate mdb_printf("%?s ", "O:"); 306*0Sstevel@tonic-gate } else { 307*0Sstevel@tonic-gate mdb_printf(","); 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate mdb_printf("zone=%s", opt); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate return (DCMD_OK); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate #define REALVP_DONE 0 316*0Sstevel@tonic-gate #define REALVP_ERR 1 317*0Sstevel@tonic-gate #define REALVP_CONTINUE 2 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate static int 320*0Sstevel@tonic-gate next_realvp(uintptr_t invp, struct vnode *outvn, uintptr_t *outvp) 321*0Sstevel@tonic-gate { 322*0Sstevel@tonic-gate char fsname[_ST_FSTYPSZ]; 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate *outvp = invp; 325*0Sstevel@tonic-gate if (mdb_vread(outvn, sizeof (struct vnode), invp) == -1) { 326*0Sstevel@tonic-gate mdb_warn("failed to read vnode at %p", invp); 327*0Sstevel@tonic-gate return (REALVP_ERR); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (read_fsname((uintptr_t)outvn->v_vfsp, fsname) == -1) 331*0Sstevel@tonic-gate return (REALVP_ERR); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * We know how to do 'realvp' for as many filesystems as possible; 335*0Sstevel@tonic-gate * for all other filesystems, we assume that the vp we are given 336*0Sstevel@tonic-gate * is the realvp. In the kernel, a realvp operation will sometimes 337*0Sstevel@tonic-gate * dig through multiple layers. Here, we only fetch the pointer 338*0Sstevel@tonic-gate * to the next layer down. This allows dcmds to print out the 339*0Sstevel@tonic-gate * various layers. 340*0Sstevel@tonic-gate */ 341*0Sstevel@tonic-gate if (strcmp(fsname, "fifofs") == 0) { 342*0Sstevel@tonic-gate fifonode_t fn; 343*0Sstevel@tonic-gate if (mdb_vread(&fn, sizeof (fn), 344*0Sstevel@tonic-gate (uintptr_t)outvn->v_data) == -1) { 345*0Sstevel@tonic-gate mdb_warn("failed to read fifonode"); 346*0Sstevel@tonic-gate return (REALVP_ERR); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate *outvp = (uintptr_t)fn.fn_realvp; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate } else if (strcmp(fsname, "namefs") == 0) { 351*0Sstevel@tonic-gate struct namenode nn; 352*0Sstevel@tonic-gate if (mdb_vread(&nn, sizeof (nn), 353*0Sstevel@tonic-gate (uintptr_t)outvn->v_data) == -1) { 354*0Sstevel@tonic-gate mdb_warn("failed to read namenode"); 355*0Sstevel@tonic-gate return (REALVP_ERR); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate *outvp = (uintptr_t)nn.nm_filevp; 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate } else if (outvn->v_type == VSOCK && outvn->v_stream != NULL) { 360*0Sstevel@tonic-gate struct stdata stream; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * Sockets have a strange and different layering scheme; we 364*0Sstevel@tonic-gate * hop over into the sockfs vnode (accessible via the stream 365*0Sstevel@tonic-gate * head) if possible. 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate if (mdb_vread(&stream, sizeof (stream), 368*0Sstevel@tonic-gate (uintptr_t)outvn->v_stream) == -1) { 369*0Sstevel@tonic-gate mdb_warn("failed to read stream data"); 370*0Sstevel@tonic-gate return (REALVP_ERR); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate *outvp = (uintptr_t)stream.sd_vnode; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate if (*outvp == invp || *outvp == NULL) 376*0Sstevel@tonic-gate return (REALVP_DONE); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate return (REALVP_CONTINUE); 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate static void 382*0Sstevel@tonic-gate pfiles_print_addr(struct sockaddr *addr) 383*0Sstevel@tonic-gate { 384*0Sstevel@tonic-gate struct sockaddr_in *s_in; 385*0Sstevel@tonic-gate struct sockaddr_un *s_un; 386*0Sstevel@tonic-gate struct sockaddr_in6 *s_in6; 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate switch (addr->sa_family) { 389*0Sstevel@tonic-gate case AF_INET: 390*0Sstevel@tonic-gate /*LINTED: alignment*/ 391*0Sstevel@tonic-gate s_in = (struct sockaddr_in *)addr; 392*0Sstevel@tonic-gate mdb_printf("AF_INET %I %d ", 393*0Sstevel@tonic-gate s_in->sin_addr.s_addr, s_in->sin_port); 394*0Sstevel@tonic-gate break; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate case AF_INET6: 397*0Sstevel@tonic-gate /*LINTED: alignment*/ 398*0Sstevel@tonic-gate s_in6 = (struct sockaddr_in6 *)addr; 399*0Sstevel@tonic-gate mdb_printf("AF_INET6 %N %d ", 400*0Sstevel@tonic-gate &(s_in6->sin6_addr), s_in6->sin6_port); 401*0Sstevel@tonic-gate break; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate case AF_UNIX: 404*0Sstevel@tonic-gate s_un = (struct sockaddr_un *)addr; 405*0Sstevel@tonic-gate mdb_printf("AF_UNIX %s ", s_un->sun_path); 406*0Sstevel@tonic-gate break; 407*0Sstevel@tonic-gate default: 408*0Sstevel@tonic-gate mdb_printf("AF_?? (%d) ", addr->sa_family); 409*0Sstevel@tonic-gate break; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate static int 415*0Sstevel@tonic-gate pfiles_get_sonode(uintptr_t vp, struct sonode *sonode) 416*0Sstevel@tonic-gate { 417*0Sstevel@tonic-gate vnode_t v; 418*0Sstevel@tonic-gate struct stdata stream; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), vp) == -1) { 421*0Sstevel@tonic-gate mdb_warn("failed to read socket vnode"); 422*0Sstevel@tonic-gate return (-1); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate if (mdb_vread(&stream, sizeof (stream), (uintptr_t)v.v_stream) == -1) { 426*0Sstevel@tonic-gate mdb_warn("failed to read stream data"); 427*0Sstevel@tonic-gate return (-1); 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), (uintptr_t)stream.sd_vnode) == -1) { 431*0Sstevel@tonic-gate mdb_warn("failed to read stream vnode"); 432*0Sstevel@tonic-gate return (-1); 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate if (mdb_vread(sonode, sizeof (struct sonode), 436*0Sstevel@tonic-gate (uintptr_t)v.v_data) == -1) { 437*0Sstevel@tonic-gate mdb_warn("failed to read sonode"); 438*0Sstevel@tonic-gate return (-1); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate return (0); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* 445*0Sstevel@tonic-gate * Do some digging to get a reasonable pathname for this vnode. 'path' 446*0Sstevel@tonic-gate * should point at a buffer of MAXPATHLEN in size. 447*0Sstevel@tonic-gate */ 448*0Sstevel@tonic-gate static int 449*0Sstevel@tonic-gate pfiles_dig_pathname(uintptr_t vp, char *path) 450*0Sstevel@tonic-gate { 451*0Sstevel@tonic-gate vnode_t v; 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate bzero(path, MAXPATHLEN); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), vp) == -1) { 456*0Sstevel@tonic-gate mdb_warn("failed to read vnode"); 457*0Sstevel@tonic-gate return (-1); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate if (v.v_path == NULL) { 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * fifo's and doors are special. Some have pathnames, and 463*0Sstevel@tonic-gate * some do not. And for these, it is pointless to go off to 464*0Sstevel@tonic-gate * mdb_vnode2path, which is very slow. 465*0Sstevel@tonic-gate * 466*0Sstevel@tonic-gate * Event ports never have a pathname. 467*0Sstevel@tonic-gate */ 468*0Sstevel@tonic-gate if (v.v_type == VFIFO || v.v_type == VDOOR || v.v_type == VPORT) 469*0Sstevel@tonic-gate return (0); 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * For sockets, we won't find a path unless we print the path 473*0Sstevel@tonic-gate * associated with the accessvp. 474*0Sstevel@tonic-gate */ 475*0Sstevel@tonic-gate if (v.v_type == VSOCK) { 476*0Sstevel@tonic-gate struct sonode sonode; 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate if (pfiles_get_sonode(vp, &sonode) == -1) { 479*0Sstevel@tonic-gate return (-1); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate vp = (uintptr_t)sonode.so_accessvp; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate /* 488*0Sstevel@tonic-gate * mdb_vnode2path will print an error for us as needed, but not 489*0Sstevel@tonic-gate * finding a pathname is not really an error, so we plow on. 490*0Sstevel@tonic-gate */ 491*0Sstevel@tonic-gate (void) mdb_vnode2path(vp, path, MAXPATHLEN); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate /* 494*0Sstevel@tonic-gate * A common problem is that device pathnames are prefixed with 495*0Sstevel@tonic-gate * /dev/../devices/. We just clean those up slightly: 496*0Sstevel@tonic-gate * /dev/../devices/<mumble> --> /devices/<mumble> 497*0Sstevel@tonic-gate * /dev/pts/../../devices/<mumble> --> /devices/<mumble> 498*0Sstevel@tonic-gate */ 499*0Sstevel@tonic-gate if (strncmp("/dev/../devices/", path, strlen("/dev/../devices/")) == 0) 500*0Sstevel@tonic-gate strcpy(path, path + 7); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate if (strncmp("/dev/pts/../../devices/", path, 503*0Sstevel@tonic-gate strlen("/dev/pts/../../devices/")) == 0) 504*0Sstevel@tonic-gate strcpy(path, path + 14); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate return (0); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate const struct fs_type { 510*0Sstevel@tonic-gate int type; 511*0Sstevel@tonic-gate const char *name; 512*0Sstevel@tonic-gate } fs_types[] = { 513*0Sstevel@tonic-gate { VNON, "NON" }, 514*0Sstevel@tonic-gate { VREG, "REG" }, 515*0Sstevel@tonic-gate { VDIR, "DIR" }, 516*0Sstevel@tonic-gate { VBLK, "BLK" }, 517*0Sstevel@tonic-gate { VCHR, "CHR" }, 518*0Sstevel@tonic-gate { VLNK, "LNK" }, 519*0Sstevel@tonic-gate { VFIFO, "FIFO" }, 520*0Sstevel@tonic-gate { VDOOR, "DOOR" }, 521*0Sstevel@tonic-gate { VPROC, "PROC" }, 522*0Sstevel@tonic-gate { VSOCK, "SOCK" }, 523*0Sstevel@tonic-gate { VPORT, "PORT" }, 524*0Sstevel@tonic-gate { VBAD, "BAD" } 525*0Sstevel@tonic-gate }; 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate #define NUM_FS_TYPES (sizeof (fs_types) / sizeof (struct fs_type)) 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate struct pfiles_cbdata { 530*0Sstevel@tonic-gate int opt_p; 531*0Sstevel@tonic-gate int fd; 532*0Sstevel@tonic-gate }; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate static int 535*0Sstevel@tonic-gate pfile_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb) 536*0Sstevel@tonic-gate { 537*0Sstevel@tonic-gate vnode_t v, layer_vn; 538*0Sstevel@tonic-gate int myfd = cb->fd; 539*0Sstevel@tonic-gate const char *type; 540*0Sstevel@tonic-gate char path[MAXPATHLEN]; 541*0Sstevel@tonic-gate uintptr_t top_vnodep, realvpp; 542*0Sstevel@tonic-gate char fsname[_ST_FSTYPSZ]; 543*0Sstevel@tonic-gate int err, i; 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate cb->fd++; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate if (addr == NULL) { 548*0Sstevel@tonic-gate return (WALK_NEXT); 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate top_vnodep = realvpp = (uintptr_t)f->f_vnode; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate if (mdb_vread(&v, sizeof (v), realvpp) == -1) { 554*0Sstevel@tonic-gate mdb_warn("failed to read vnode"); 555*0Sstevel@tonic-gate return (DCMD_ERR); 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate type = "?"; 559*0Sstevel@tonic-gate for (i = 0; i <= NUM_FS_TYPES; i++) { 560*0Sstevel@tonic-gate if (fs_types[i].type == v.v_type) 561*0Sstevel@tonic-gate type = fs_types[i].name; 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate do { 565*0Sstevel@tonic-gate uintptr_t next_realvpp; 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate err = next_realvp(realvpp, &layer_vn, &next_realvpp); 568*0Sstevel@tonic-gate if (next_realvpp != NULL) 569*0Sstevel@tonic-gate realvpp = next_realvpp; 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate } while (err == REALVP_CONTINUE); 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate if (err == REALVP_ERR) { 574*0Sstevel@tonic-gate mdb_warn("failed to do realvp() for %p", realvpp); 575*0Sstevel@tonic-gate return (DCMD_ERR); 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate if (read_fsname((uintptr_t)layer_vn.v_vfsp, fsname) == -1) 579*0Sstevel@tonic-gate return (DCMD_ERR); 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate mdb_printf("%4d %4s %?0p ", myfd, type, top_vnodep); 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate if (cb->opt_p) { 584*0Sstevel@tonic-gate if (pfiles_dig_pathname(top_vnodep, path) == -1) 585*0Sstevel@tonic-gate return (DCMD_ERR); 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate mdb_printf("%s\n", path); 588*0Sstevel@tonic-gate return (DCMD_OK); 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate /* 592*0Sstevel@tonic-gate * Sockets generally don't have interesting pathnames; we only 593*0Sstevel@tonic-gate * show those in the '-p' view. 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate path[0] = '\0'; 596*0Sstevel@tonic-gate if (v.v_type != VSOCK) { 597*0Sstevel@tonic-gate if (pfiles_dig_pathname(top_vnodep, path) == -1) 598*0Sstevel@tonic-gate return (DCMD_ERR); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate mdb_printf("%s%s", path, path[0] == '\0' ? "" : " "); 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate switch (v.v_type) { 603*0Sstevel@tonic-gate case VDOOR: 604*0Sstevel@tonic-gate { 605*0Sstevel@tonic-gate door_node_t doornode; 606*0Sstevel@tonic-gate proc_t pr; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate if (mdb_vread(&doornode, sizeof (doornode), 609*0Sstevel@tonic-gate (uintptr_t)layer_vn.v_data) == -1) { 610*0Sstevel@tonic-gate mdb_warn("failed to read door_node"); 611*0Sstevel@tonic-gate return (DCMD_ERR); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate if (mdb_vread(&pr, sizeof (pr), 615*0Sstevel@tonic-gate (uintptr_t)doornode.door_target) == -1) { 616*0Sstevel@tonic-gate mdb_warn("failed to read door server process %p", 617*0Sstevel@tonic-gate doornode.door_target); 618*0Sstevel@tonic-gate return (DCMD_ERR); 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate mdb_printf("[door to '%s' (proc=%p)]", pr.p_user.u_comm, 621*0Sstevel@tonic-gate doornode.door_target); 622*0Sstevel@tonic-gate break; 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate case VSOCK: 626*0Sstevel@tonic-gate { 627*0Sstevel@tonic-gate struct sonode sonode; 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate if (pfiles_get_sonode(realvpp, &sonode) == -1) 630*0Sstevel@tonic-gate return (DCMD_ERR); 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* 633*0Sstevel@tonic-gate * If the address is cached in the sonode, use it; otherwise, 634*0Sstevel@tonic-gate * we print nothing. 635*0Sstevel@tonic-gate */ 636*0Sstevel@tonic-gate if (sonode.so_state & SS_LADDR_VALID) { 637*0Sstevel@tonic-gate struct sockaddr *laddr = 638*0Sstevel@tonic-gate mdb_alloc(sonode.so_laddr_len, UM_SLEEP); 639*0Sstevel@tonic-gate if (mdb_vread(laddr, sonode.so_laddr_len, 640*0Sstevel@tonic-gate (uintptr_t)sonode.so_laddr_sa) == -1) { 641*0Sstevel@tonic-gate mdb_warn("failed to read sonode socket addr"); 642*0Sstevel@tonic-gate return (DCMD_ERR); 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate mdb_printf("socket: "); 646*0Sstevel@tonic-gate pfiles_print_addr(laddr); 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate if (sonode.so_state & SS_FADDR_VALID) { 650*0Sstevel@tonic-gate struct sockaddr *faddr = 651*0Sstevel@tonic-gate mdb_alloc(sonode.so_faddr_len, UM_SLEEP); 652*0Sstevel@tonic-gate if (mdb_vread(faddr, sonode.so_faddr_len, 653*0Sstevel@tonic-gate (uintptr_t)sonode.so_faddr_sa) == -1) { 654*0Sstevel@tonic-gate mdb_warn("failed to read sonode remote addr"); 655*0Sstevel@tonic-gate return (DCMD_ERR); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate mdb_printf("remote: "); 659*0Sstevel@tonic-gate pfiles_print_addr(faddr); 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate break; 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate case VPORT: 665*0Sstevel@tonic-gate mdb_printf("[event port (port=%p)]", v.v_data); 666*0Sstevel@tonic-gate break; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate case VPROC: 669*0Sstevel@tonic-gate { 670*0Sstevel@tonic-gate prnode_t prnode; 671*0Sstevel@tonic-gate prcommon_t prcommon; 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate if (mdb_vread(&prnode, sizeof (prnode), 674*0Sstevel@tonic-gate (uintptr_t)layer_vn.v_data) == -1) { 675*0Sstevel@tonic-gate mdb_warn("failed to read prnode"); 676*0Sstevel@tonic-gate return (DCMD_ERR); 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate if (mdb_vread(&prcommon, sizeof (prcommon), 680*0Sstevel@tonic-gate (uintptr_t)prnode.pr_common) == -1) { 681*0Sstevel@tonic-gate mdb_warn("failed to read prcommon %p", 682*0Sstevel@tonic-gate prnode.pr_common); 683*0Sstevel@tonic-gate return (DCMD_ERR); 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate mdb_printf("(proc=%p)", prcommon.prc_proc); 687*0Sstevel@tonic-gate break; 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate default: 691*0Sstevel@tonic-gate break; 692*0Sstevel@tonic-gate } 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate mdb_printf("\n"); 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate return (WALK_NEXT); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate static int 701*0Sstevel@tonic-gate file_t_callback(uintptr_t addr, const struct file *f, struct pfiles_cbdata *cb) 702*0Sstevel@tonic-gate { 703*0Sstevel@tonic-gate int myfd = cb->fd; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate cb->fd++; 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate if (addr == NULL) { 708*0Sstevel@tonic-gate return (WALK_NEXT); 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate /* 712*0Sstevel@tonic-gate * We really need 20 digits to print a 64-bit offset_t, but this 713*0Sstevel@tonic-gate * is exceedingly rare, so we cheat and assume a column width of 10 714*0Sstevel@tonic-gate * digits, in order to fit everything cleanly into 80 columns. 715*0Sstevel@tonic-gate */ 716*0Sstevel@tonic-gate mdb_printf("%?0p %4d %8x %?0p %10lld %?0p %4d\n", 717*0Sstevel@tonic-gate addr, myfd, f->f_flag, f->f_vnode, f->f_offset, f->f_cred, 718*0Sstevel@tonic-gate f->f_count); 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate return (WALK_NEXT); 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate int 724*0Sstevel@tonic-gate pfiles(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 725*0Sstevel@tonic-gate { 726*0Sstevel@tonic-gate int opt_f = 0; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate struct pfiles_cbdata cb; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate bzero(&cb, sizeof (cb)); 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 733*0Sstevel@tonic-gate return (DCMD_USAGE); 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate if (mdb_getopts(argc, argv, 736*0Sstevel@tonic-gate 'p', MDB_OPT_SETBITS, TRUE, &cb.opt_p, 737*0Sstevel@tonic-gate 'f', MDB_OPT_SETBITS, TRUE, &opt_f, NULL) != argc) 738*0Sstevel@tonic-gate return (DCMD_USAGE); 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate if (opt_f) { 741*0Sstevel@tonic-gate mdb_printf("%<u>%?s %4s %8s %?s %10s %?s %4s%</u>\n", "FILE", 742*0Sstevel@tonic-gate "FD", "FLAG", "VNODE", "OFFSET", "CRED", "CNT"); 743*0Sstevel@tonic-gate if (mdb_pwalk("allfile", (mdb_walk_cb_t)file_t_callback, &cb, 744*0Sstevel@tonic-gate addr) == -1) { 745*0Sstevel@tonic-gate mdb_warn("failed to walk 'allfile'"); 746*0Sstevel@tonic-gate return (DCMD_ERR); 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate } else { 749*0Sstevel@tonic-gate mdb_printf("%<u>%-4s %4s %?s ", "FD", "TYPE", "VNODE"); 750*0Sstevel@tonic-gate if (cb.opt_p) 751*0Sstevel@tonic-gate mdb_printf("PATH"); 752*0Sstevel@tonic-gate else 753*0Sstevel@tonic-gate mdb_printf("INFO"); 754*0Sstevel@tonic-gate mdb_printf("%</u>\n"); 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate if (mdb_pwalk("allfile", (mdb_walk_cb_t)pfile_callback, &cb, 757*0Sstevel@tonic-gate addr) == -1) { 758*0Sstevel@tonic-gate mdb_warn("failed to walk 'allfile'"); 759*0Sstevel@tonic-gate return (DCMD_ERR); 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate return (DCMD_OK); 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate void 768*0Sstevel@tonic-gate pfiles_help(void) 769*0Sstevel@tonic-gate { 770*0Sstevel@tonic-gate mdb_printf( 771*0Sstevel@tonic-gate "Given the address of a process, print information about files\n" 772*0Sstevel@tonic-gate "which the process has open. By default, this includes decoded\n" 773*0Sstevel@tonic-gate "information about the file depending on file and filesystem type\n" 774*0Sstevel@tonic-gate "\n" 775*0Sstevel@tonic-gate "\t-p\tPathnames; omit decoded information. Only display " 776*0Sstevel@tonic-gate "pathnames\n" 777*0Sstevel@tonic-gate "\t-f\tfile_t view; show the file_t structure corresponding to " 778*0Sstevel@tonic-gate "the fd\n"); 779*0Sstevel@tonic-gate } 780