Mercurial > illumos > onarm
diff usr/src/cmd/mdb/common/modules/nsmb/nsmb.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c Tue Jun 02 18:56:50 2009 +0900 @@ -0,0 +1,575 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#pragma ident "@(#)nsmb.c 1.1 08/02/13 SMI" + +#include <sys/mdb_modapi.h> +#include <sys/types.h> + +#include "smb_conn.h" +#include "smb_rq.h" +#include "smb_pass.h" + +#define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */ +#define OPT_RECURSE 0x0002 /* recursive display */ + +/* + * We need to read in a private copy + * of every string we want to print out. + */ +void +print_str(uintptr_t addr) +{ + char buf[32]; + int len, mx = sizeof (buf) - 4; + + if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) { + mdb_printf(" (%p)", addr); + } else { + if (len > mx) + strcpy(&buf[mx], "..."); + mdb_printf(" %s", buf); + } +} + + +/* + * Walker for smb_connobj_t structures, including + * smb_vc_t and smb_share_t which "inherit" from it. + * Tricky: Exploit the "inheritance" of smb_connobj_t + * with common functions for walk_init, walk_next. + */ +typedef struct smb_co_walk_data { + uintptr_t pp; + int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */ + int size; /* sizeof (union member) */ + union co_u { + smb_connobj_t co; /* copy of the list element */ + smb_vc_t vc; + smb_share_t ss; + } u; +} smb_co_walk_data_t; + +/* + * Common walk_init for walking structs inherited + * from smb_connobj_t (smb_vc_t, smb_share_t) + */ +int +smb_co_walk_init(mdb_walk_state_t *wsp, int level) +{ + smb_co_walk_data_t *smbw; + size_t psz; + + if (wsp->walk_addr == NULL) + return (WALK_ERR); + + smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC); + wsp->walk_data = smbw; + + /* + * Save the parent pointer for later checks, and + * the level so we know which union member it is. + * Also the size of this union member. + */ + smbw->pp = wsp->walk_addr; + smbw->level = level; + switch (level) { + case SMBL_SM: + smbw->size = sizeof (smbw->u.co); + break; + case SMBL_VC: + smbw->size = sizeof (smbw->u.vc); + break; + case SMBL_SHARE: + smbw->size = sizeof (smbw->u.ss); + break; + default: + smbw->size = sizeof (smbw->u); + break; + } + + /* + * Read in the parent object. Just need the + * invariant part (smb_connobj_t) so we can + * get the list of children below it. + */ + psz = sizeof (smbw->u.co); + if (mdb_vread(&smbw->u.co, psz, smbw->pp) != psz) { + mdb_warn("cannot read connobj from %p", smbw->pp); + return (WALK_ERR); + } + + /* + * Finally, setup to walk the list of children. + */ + wsp->walk_addr = (uintptr_t)smbw->u.co.co_children.slh_first; + + return (WALK_NEXT); +} + +/* + * Walk the (global) VC list. + */ +int +smb_vc_walk_init(mdb_walk_state_t *wsp) +{ + GElf_Sym sym; + + if (wsp->walk_addr != NULL) { + mdb_warn("::walk smb_vc only supports global walks\n"); + return (WALK_ERR); + } + + /* Locate the VC list head. */ + if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym)) { + mdb_warn("failed to lookup `smb_vclist'\n"); + return (WALK_ERR); + } + wsp->walk_addr = sym.st_value; + + return (smb_co_walk_init(wsp, SMBL_VC)); +} + +/* + * Walk the share list below some VC. + */ +int +smb_ss_walk_init(mdb_walk_state_t *wsp) +{ + + /* + * Initial walk_addr is address of parent (VC) + */ + if (wsp->walk_addr == 0) { + mdb_warn("::walk smb_ss does not support global walks\n"); + return (WALK_ERR); + } + + return (smb_co_walk_init(wsp, SMBL_SHARE)); +} + +/* + * Common walk_step for walking structs inherited + * from smb_connobj_t (smb_vc_t, smb_share_t) + */ +int +smb_co_walk_step(mdb_walk_state_t *wsp) +{ + smb_co_walk_data_t *smbw = wsp->walk_data; + int status; + + if (wsp->walk_addr == NULL) + return (WALK_DONE); + + if (mdb_vread(&smbw->u, smbw->size, wsp->walk_addr) + != smbw->size) { + mdb_warn("cannot read connobj from %p", wsp->walk_addr); + return (WALK_ERR); + } + + /* XXX: Sanity check level? parent pointer? */ + + status = wsp->walk_callback(wsp->walk_addr, &smbw->u, + wsp->walk_cbdata); + + wsp->walk_addr = (uintptr_t)smbw->u.co.co_next.sle_next; + + return (status); +} + + +/* + * Dcmd (and callback function) to print a summary of + * all VCs, and optionally all shares under each VC. + */ + +typedef struct smb_co_cbdata { + int flags; /* OPT_... */ + int printed_header; +} smb_co_cbdata_t; + +/* + * Call-back function for walking a share list. + */ +int +smb_ss_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_share_t *ssp = data; + smb_co_cbdata_t *cbd = arg; + + mdb_printf(" %-p", addr); + print_str((uintptr_t)ssp->ss_name); + mdb_printf("\n"); + + if (cbd->flags & OPT_VERBOSE) { + mdb_inc_indent(2); + /* Anything wanted here? */ + mdb_dec_indent(2); + } + + return (WALK_NEXT); +} + +/* + * Call-back function for walking the VC list. + */ +int +smb_vc_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_vc_t *vcp = data; + smb_co_cbdata_t *cbd = arg; + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smb_vc_t uid server user\n"); + } + + mdb_printf("%-p", addr); + mdb_printf(" %d", vcp->vc_uid); + print_str((uintptr_t)vcp->vc_srvname); + print_str((uintptr_t)vcp->vc_username); + mdb_printf("\n"); + + if (cbd->flags & OPT_RECURSE) { + mdb_inc_indent(2); + if (mdb_pwalk("nsmb_ss", smb_ss_cb, cbd, addr) < 0) { + mdb_warn("failed to walk 'nsmb_ss'"); + /* Don't: return (WALK_ERR); */ + } + mdb_dec_indent(2); + } + + return (WALK_NEXT); +} + +int +smb_vc_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + smb_co_cbdata_t cbd; + smb_vc_t *vcp; + size_t vcsz; + + memset(&cbd, 0, sizeof (cbd)); + + if (mdb_getopts(argc, argv, + 'r', MDB_OPT_SETBITS, OPT_RECURSE, &cbd.flags, + 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd.flags, + NULL) != argc) { + return (DCMD_USAGE); + } + + if (!(flags & DCMD_ADDRSPEC)) { + if (mdb_walk("nsmb_vc", smb_vc_cb, &cbd) == -1) { + mdb_warn("failed to walk 'nsmb_vc'"); + return (DCMD_ERR); + } + return (DCMD_OK); + } + + vcsz = sizeof (*vcp); + vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC); + if (mdb_vread(vcp, vcsz, addr) != vcsz) { + mdb_warn("cannot read VC from %p", addr); + return (DCMD_ERR); + } + smb_vc_cb(addr, vcp, &cbd); + + return (DCMD_OK); +} + +void +smb_vc_help(void) +{ + mdb_printf("Options:\n" + " -r recursive display of share lists\n" + " -v be verbose when displaying smb_vc\n"); +} + +/* + * Walker for the request list on a VC, + * and dcmd to show a summary. + */ +int +rqlist_walk_init(mdb_walk_state_t *wsp) +{ + struct smb_rqhead rqh; + uintptr_t addr; + + /* + * Initial walk_addr is the address of the VC. + * Add offsetof(iod_rqlist) to get the rqhead. + */ + if (wsp->walk_addr == 0) { + mdb_warn("::walk smb_ss does not support global walks\n"); + return (WALK_ERR); + } + addr = wsp->walk_addr; + addr += OFFSETOF(smb_vc_t, iod_rqlist); + + if (mdb_vread(&rqh, sizeof (rqh), addr) == -1) { + mdb_warn("failed to read smb_rqhead at %p", addr); + return (WALK_ERR); + } + wsp->walk_addr = (uintptr_t)rqh.tqh_first; + + return (WALK_NEXT); +} + +int +rqlist_walk_step(mdb_walk_state_t *wsp) +{ + smb_rq_t rq; + int status; + + if (wsp->walk_addr == NULL) + return (WALK_DONE); + + if (mdb_vread(&rq, sizeof (rq), wsp->walk_addr) == -1) { + mdb_warn("cannot read smb_rq from %p", wsp->walk_addr); + return (WALK_ERR); + } + + status = wsp->walk_callback(wsp->walk_addr, &rq, + wsp->walk_cbdata); + + wsp->walk_addr = (uintptr_t)rq.sr_link.tqe_next; + + return (status); +} + +typedef struct rqlist_cbdata { + int printed_header; + uintptr_t uid; /* optional filtering by UID */ +} rqlist_cbdata_t; + +int +rqlist_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_rq_t *rq = data; + rqlist_cbdata_t *cbd = arg; + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smb_rq_t MID cmd sr_state sr_flags\n"); + } + + mdb_printf(" %-p", addr); /* smb_rq_t */ + mdb_printf(" x%04x", rq->sr_mid); + mdb_printf(" x%02x", rq->sr_cmd); + mdb_printf(" %d", rq->sr_state); + mdb_printf(" x%x", rq->sr_flags); + mdb_printf("\n"); + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +int +rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + rqlist_cbdata_t cbd; + + memset(&cbd, 0, sizeof (cbd)); + + /* + * Initial walk_addr is address of parent (VC) + */ + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("address required\n"); + return (DCMD_ERR); + } + + if (mdb_pwalk("nsmb_rqlist", rqlist_cb, &cbd, addr) == -1) { + mdb_warn("failed to walk 'nsmb_rqlist'"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + + +/* + * AVL walker for the passwords AVL tree, + * and dcmd to show a summary. + */ +static int +pwtree_walk_init(mdb_walk_state_t *wsp) +{ + GElf_Sym sym; + + if (wsp->walk_addr != NULL) { + mdb_warn("pwtree walk only supports global walks\n"); + return (WALK_ERR); + } + + if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym) == -1) { + mdb_warn("failed to find symbol 'smb_ptd'"); + return (WALK_ERR); + } + + wsp->walk_addr = (uintptr_t)sym.st_value; + + if (mdb_layered_walk("avl", wsp) == -1) { + mdb_warn("failed to walk 'avl'\n"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +static int +pwtree_walk_step(mdb_walk_state_t *wsp) +{ + smb_passid_t ptnode; + + if (mdb_vread(&ptnode, sizeof (ptnode), wsp->walk_addr) == -1) { + mdb_warn("failed to read smb_passid_t at %p", wsp->walk_addr); + return (WALK_ERR); + } + + return (wsp->walk_callback(wsp->walk_addr, &ptnode, wsp->walk_cbdata)); +} + +typedef struct pwtree_cbdata { + int printed_header; + uid_t uid; /* optional filtering by UID */ +} pwtree_cbdata_t; + +int +pwtree_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_passid_t *ptn = data; + pwtree_cbdata_t *cbd = arg; + + /* Optional filtering by UID. */ + if (cbd->uid != (uid_t)-1 && cbd->uid != ptn->uid) { + return (WALK_NEXT); + } + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smb_passid_t UID domain user\n"); + } + + mdb_printf(" %-p", addr); /* smb_passid_t */ + mdb_printf(" %d", (uintptr_t)ptn->uid); + print_str((uintptr_t)ptn->srvdom); + print_str((uintptr_t)ptn->username); + mdb_printf("\n"); + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +int +pwtree_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + pwtree_cbdata_t cbd; + char *uid_str = NULL; + char buf[32]; + + memset(&cbd, 0, sizeof (cbd)); + + if (mdb_getopts(argc, argv, + 'u', MDB_OPT_STR, &uid_str, NULL) != argc) { + return (DCMD_USAGE); + } + if (uid_str) { + /* + * Want the the default radix to be 10 here. + * If the string has some kind of radix prefix, + * just use that as-is, otherwise prepend "0t". + * Cheating on the "not a digit" test, but + * mdb_strtoull will do a real syntax check. + */ + if (uid_str[0] == '0' && uid_str[1] > '9') { + cbd.uid = (uid_t)mdb_strtoull(uid_str); + } else { + strcpy(buf, "0t"); + strlcat(buf, uid_str, sizeof (buf)); + cbd.uid = (uid_t)mdb_strtoull(buf); + } + } else + cbd.uid = (uid_t)-1; + + if (flags & DCMD_ADDRSPEC) { + mdb_warn("address not allowed\n"); + return (DCMD_ERR); + } + + if (mdb_pwalk("nsmb_pwtree", pwtree_cb, &cbd, 0) == -1) { + mdb_warn("failed to walk 'nsmb_pwtree'"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + +void +pwtree_help(void) +{ + mdb_printf("Options:\n" + " -u uid show only entries belonging to uid (decimal)\n"); +} + + +static const mdb_dcmd_t dcmds[] = { + { "nsmb_vc", "?[-rv]", + "show smb_vc (or list)", + smb_vc_dcmd, smb_vc_help }, + { "nsmb_rqlist", ":", + "show smb_rq list on a VC", + rqlist_dcmd, NULL }, + { "nsmb_pwtree", "?[-u uid]", + "list smb_passid_t (password tree)", + pwtree_dcmd, pwtree_help }, + {NULL} +}; + +static const mdb_walker_t walkers[] = { + { "nsmb_vc", "walk nsmb VC list", + smb_vc_walk_init, smb_co_walk_step, NULL }, + { "nsmb_ss", "walk nsmb share list for some VC", + smb_ss_walk_init, smb_co_walk_step, NULL }, + { "nsmb_rqlist", "walk request list for some VC", + rqlist_walk_init, rqlist_walk_step, NULL }, + { "nsmb_pwtree", "walk passord AVL tree", + pwtree_walk_init, pwtree_walk_step, NULL }, + {NULL} +}; + +static const mdb_modinfo_t modinfo = { + MDB_API_VERSION, + dcmds, + walkers +}; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +}