xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/zone.c (revision 13096:b02331b7b26d)
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
58111SJordan.Vaughan@Sun.com  * Common Development and Distribution License (the "License").
68111SJordan.Vaughan@Sun.com  * 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*13096SJordan.Vaughan@Sun.com  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <mdb/mdb_param.h>
260Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
270Sstevel@tonic-gate #include <mdb/mdb_ks.h>
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "zone.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <stddef.h>
320Sstevel@tonic-gate #include <sys/zone.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #define	ZONE_NAMELEN	20
350Sstevel@tonic-gate #ifdef _LP64
360Sstevel@tonic-gate #define	ZONE_PATHLEN	32
370Sstevel@tonic-gate #else
380Sstevel@tonic-gate #define	ZONE_PATHLEN	40
390Sstevel@tonic-gate #endif
400Sstevel@tonic-gate 
41*13096SJordan.Vaughan@Sun.com /*
42*13096SJordan.Vaughan@Sun.com  * Names corresponding to zone_status_t values in sys/zone.h
43*13096SJordan.Vaughan@Sun.com  */
44*13096SJordan.Vaughan@Sun.com char *zone_status_names[] = {
45*13096SJordan.Vaughan@Sun.com 	"uninitialized",	/* ZONE_IS_UNINITIALIZED */
46*13096SJordan.Vaughan@Sun.com 	"initialized",		/* ZONE_IS_INITIALIZED */
47*13096SJordan.Vaughan@Sun.com 	"ready",		/* ZONE_IS_READY */
48*13096SJordan.Vaughan@Sun.com 	"booting",		/* ZONE_IS_BOOTING */
49*13096SJordan.Vaughan@Sun.com 	"running",		/* ZONE_IS_RUNNING */
50*13096SJordan.Vaughan@Sun.com 	"shutting_down",	/* ZONE_IS_SHUTTING_DOWN */
51*13096SJordan.Vaughan@Sun.com 	"empty",		/* ZONE_IS_EMPTY */
52*13096SJordan.Vaughan@Sun.com 	"down",			/* ZONE_IS_DOWN */
53*13096SJordan.Vaughan@Sun.com 	"dying",		/* ZONE_IS_DYING */
54*13096SJordan.Vaughan@Sun.com 	"dead"			/* ZONE_IS_DEAD */
55*13096SJordan.Vaughan@Sun.com };
56*13096SJordan.Vaughan@Sun.com 
570Sstevel@tonic-gate int
zoneprt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)580Sstevel@tonic-gate zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	zone_t zn;
610Sstevel@tonic-gate 	char name[ZONE_NAMELEN];
620Sstevel@tonic-gate 	char path[ZONE_PATHLEN];
630Sstevel@tonic-gate 	int len;
64*13096SJordan.Vaughan@Sun.com 	uint_t vopt_given;
65*13096SJordan.Vaughan@Sun.com 	uint_t ropt_given;
660Sstevel@tonic-gate 
67*13096SJordan.Vaughan@Sun.com 	if (argc > 2)
680Sstevel@tonic-gate 		return (DCMD_USAGE);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
710Sstevel@tonic-gate 		if (mdb_walk_dcmd("zone", "zone", argc, argv) == -1) {
720Sstevel@tonic-gate 			mdb_warn("can't walk zones");
730Sstevel@tonic-gate 			return (DCMD_ERR);
740Sstevel@tonic-gate 		}
750Sstevel@tonic-gate 		return (DCMD_OK);
760Sstevel@tonic-gate 	}
77*13096SJordan.Vaughan@Sun.com 
78*13096SJordan.Vaughan@Sun.com 	/*
79*13096SJordan.Vaughan@Sun.com 	 * Get the optional -r (reference counts) and -v (verbose output)
80*13096SJordan.Vaughan@Sun.com 	 * arguments.
81*13096SJordan.Vaughan@Sun.com 	 */
82*13096SJordan.Vaughan@Sun.com 	vopt_given = FALSE;
83*13096SJordan.Vaughan@Sun.com 	ropt_given = FALSE;
84*13096SJordan.Vaughan@Sun.com 	if (argc > 0 && mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE,
85*13096SJordan.Vaughan@Sun.com 	    &vopt_given, 'r', MDB_OPT_SETBITS, TRUE, &ropt_given, NULL) != argc)
86*13096SJordan.Vaughan@Sun.com 		return (DCMD_USAGE);
87*13096SJordan.Vaughan@Sun.com 
88*13096SJordan.Vaughan@Sun.com 	/*
89*13096SJordan.Vaughan@Sun.com 	 * -v can only be specified with -r.
90*13096SJordan.Vaughan@Sun.com 	 */
91*13096SJordan.Vaughan@Sun.com 	if (vopt_given == TRUE && ropt_given == FALSE)
92*13096SJordan.Vaughan@Sun.com 		return (DCMD_USAGE);
93*13096SJordan.Vaughan@Sun.com 
94*13096SJordan.Vaughan@Sun.com 	/*
95*13096SJordan.Vaughan@Sun.com 	 * Print a table header, if necessary.
96*13096SJordan.Vaughan@Sun.com 	 */
970Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
98*13096SJordan.Vaughan@Sun.com 		if (ropt_given == FALSE)
99*13096SJordan.Vaughan@Sun.com 			mdb_printf("%<u>%?s %6s %-13s %-20s %-s%</u>\n",
100*13096SJordan.Vaughan@Sun.com 			    "ADDR", "ID", "STATUS", "NAME", "PATH");
101*13096SJordan.Vaughan@Sun.com 		else
102*13096SJordan.Vaughan@Sun.com 			mdb_printf("%<u>%?s %6s %10s %10s %-20s%</u>\n",
103*13096SJordan.Vaughan@Sun.com 			    "ADDR", "ID", "REFS", "CREFS", "NAME");
1040Sstevel@tonic-gate 	}
105*13096SJordan.Vaughan@Sun.com 
106*13096SJordan.Vaughan@Sun.com 	/*
107*13096SJordan.Vaughan@Sun.com 	 * Read the zone_t structure at the given address and read its name.
108*13096SJordan.Vaughan@Sun.com 	 */
1090Sstevel@tonic-gate 	if (mdb_vread(&zn, sizeof (zone_t), addr) == -1) {
1100Sstevel@tonic-gate 		mdb_warn("can't read zone_t structure at %p", addr);
1110Sstevel@tonic-gate 		return (DCMD_ERR);
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 	len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zn.zone_name);
1140Sstevel@tonic-gate 	if (len > 0) {
1150Sstevel@tonic-gate 		if (len == ZONE_NAMELEN)
1160Sstevel@tonic-gate 			(void) strcpy(&name[len - 4], "...");
1170Sstevel@tonic-gate 	} else {
1180Sstevel@tonic-gate 		(void) strcpy(name, "??");
1190Sstevel@tonic-gate 	}
120*13096SJordan.Vaughan@Sun.com 
121*13096SJordan.Vaughan@Sun.com 	if (ropt_given == FALSE) {
122*13096SJordan.Vaughan@Sun.com 		char *statusp;
123*13096SJordan.Vaughan@Sun.com 
124*13096SJordan.Vaughan@Sun.com 		/*
125*13096SJordan.Vaughan@Sun.com 		 * Default display
126*13096SJordan.Vaughan@Sun.com 		 * Fetch the zone's path and print the results.
127*13096SJordan.Vaughan@Sun.com 		 */
128*13096SJordan.Vaughan@Sun.com 		len = mdb_readstr(path, ZONE_PATHLEN,
129*13096SJordan.Vaughan@Sun.com 		    (uintptr_t)zn.zone_rootpath);
130*13096SJordan.Vaughan@Sun.com 		if (len > 0) {
131*13096SJordan.Vaughan@Sun.com 			if (len == ZONE_PATHLEN)
132*13096SJordan.Vaughan@Sun.com 				(void) strcpy(&path[len - 4], "...");
133*13096SJordan.Vaughan@Sun.com 		} else {
134*13096SJordan.Vaughan@Sun.com 			(void) strcpy(path, "??");
135*13096SJordan.Vaughan@Sun.com 		}
136*13096SJordan.Vaughan@Sun.com 		if (zn.zone_status >= ZONE_IS_UNINITIALIZED && zn.zone_status <=
137*13096SJordan.Vaughan@Sun.com 		    ZONE_IS_DEAD)
138*13096SJordan.Vaughan@Sun.com 			statusp = zone_status_names[zn.zone_status];
139*13096SJordan.Vaughan@Sun.com 		else
140*13096SJordan.Vaughan@Sun.com 			statusp = "???";
141*13096SJordan.Vaughan@Sun.com 		mdb_printf("%0?p %6d %-13s %-20s %s\n", addr, zn.zone_id,
142*13096SJordan.Vaughan@Sun.com 		    statusp, name, path);
1430Sstevel@tonic-gate 	} else {
144*13096SJordan.Vaughan@Sun.com 		/*
145*13096SJordan.Vaughan@Sun.com 		 * Display the zone's reference counts.
146*13096SJordan.Vaughan@Sun.com 		 * Display the zone's subsystem-specific reference counts if
147*13096SJordan.Vaughan@Sun.com 		 * the user specified the '-v' option.
148*13096SJordan.Vaughan@Sun.com 		 */
149*13096SJordan.Vaughan@Sun.com 		mdb_printf("%0?p %6d %10u %10u %-20s\n", addr, zn.zone_id,
150*13096SJordan.Vaughan@Sun.com 		    zn.zone_ref, zn.zone_cred_ref, name);
151*13096SJordan.Vaughan@Sun.com 		if (vopt_given == TRUE) {
152*13096SJordan.Vaughan@Sun.com 			GElf_Sym subsys_names_sym;
153*13096SJordan.Vaughan@Sun.com 			uintptr_t **zone_ref_subsys_names;
154*13096SJordan.Vaughan@Sun.com 			uint_t num_subsys;
155*13096SJordan.Vaughan@Sun.com 			uint_t n;
156*13096SJordan.Vaughan@Sun.com 
157*13096SJordan.Vaughan@Sun.com 			/*
158*13096SJordan.Vaughan@Sun.com 			 * Read zone_ref_subsys_names from the kernel image.
159*13096SJordan.Vaughan@Sun.com 			 */
160*13096SJordan.Vaughan@Sun.com 			if (mdb_lookup_by_name("zone_ref_subsys_names",
161*13096SJordan.Vaughan@Sun.com 			    &subsys_names_sym) != 0) {
162*13096SJordan.Vaughan@Sun.com 				mdb_warn("can't find zone_ref_subsys_names");
163*13096SJordan.Vaughan@Sun.com 				return (DCMD_ERR);
164*13096SJordan.Vaughan@Sun.com 			}
165*13096SJordan.Vaughan@Sun.com 			if (subsys_names_sym.st_size != ZONE_REF_NUM_SUBSYS *
166*13096SJordan.Vaughan@Sun.com 			    sizeof (char *)) {
167*13096SJordan.Vaughan@Sun.com 				mdb_warn("number of subsystems in target "
168*13096SJordan.Vaughan@Sun.com 				    "differs from what mdb expects (mismatched"
169*13096SJordan.Vaughan@Sun.com 				    " kernel versions?)");
170*13096SJordan.Vaughan@Sun.com 				if (subsys_names_sym.st_size <
171*13096SJordan.Vaughan@Sun.com 				    ZONE_REF_NUM_SUBSYS * sizeof (char *))
172*13096SJordan.Vaughan@Sun.com 					num_subsys = subsys_names_sym.st_size /
173*13096SJordan.Vaughan@Sun.com 					    sizeof (char *);
174*13096SJordan.Vaughan@Sun.com 				else
175*13096SJordan.Vaughan@Sun.com 					num_subsys = ZONE_REF_NUM_SUBSYS;
176*13096SJordan.Vaughan@Sun.com 			} else {
177*13096SJordan.Vaughan@Sun.com 				num_subsys = ZONE_REF_NUM_SUBSYS;
178*13096SJordan.Vaughan@Sun.com 			}
179*13096SJordan.Vaughan@Sun.com 			if ((zone_ref_subsys_names = mdb_alloc(
180*13096SJordan.Vaughan@Sun.com 			    subsys_names_sym.st_size, UM_GC)) == NULL) {
181*13096SJordan.Vaughan@Sun.com 				mdb_warn("out of memory");
182*13096SJordan.Vaughan@Sun.com 				return (DCMD_ERR);
183*13096SJordan.Vaughan@Sun.com 			}
184*13096SJordan.Vaughan@Sun.com 			if (mdb_readvar(zone_ref_subsys_names,
185*13096SJordan.Vaughan@Sun.com 			    "zone_ref_subsys_names") == -1) {
186*13096SJordan.Vaughan@Sun.com 				mdb_warn("can't find zone_ref_subsys_names");
187*13096SJordan.Vaughan@Sun.com 				return (DCMD_ERR);
188*13096SJordan.Vaughan@Sun.com 			}
189*13096SJordan.Vaughan@Sun.com 
190*13096SJordan.Vaughan@Sun.com 			/*
191*13096SJordan.Vaughan@Sun.com 			 * Display each subsystem's reference count if it's
192*13096SJordan.Vaughan@Sun.com 			 * nonzero.
193*13096SJordan.Vaughan@Sun.com 			 */
194*13096SJordan.Vaughan@Sun.com 			mdb_inc_indent(7);
195*13096SJordan.Vaughan@Sun.com 			for (n = 0; n < num_subsys; ++n) {
196*13096SJordan.Vaughan@Sun.com 				char subsys_name[16];
197*13096SJordan.Vaughan@Sun.com 
198*13096SJordan.Vaughan@Sun.com 				/*
199*13096SJordan.Vaughan@Sun.com 				 * Skip subsystems lacking outstanding
200*13096SJordan.Vaughan@Sun.com 				 * references.
201*13096SJordan.Vaughan@Sun.com 				 */
202*13096SJordan.Vaughan@Sun.com 				if (zn.zone_subsys_ref[n] == 0)
203*13096SJordan.Vaughan@Sun.com 					continue;
204*13096SJordan.Vaughan@Sun.com 
205*13096SJordan.Vaughan@Sun.com 				/*
206*13096SJordan.Vaughan@Sun.com 				 * Each subsystem's name must be read from
207*13096SJordan.Vaughan@Sun.com 				 * the target's image.
208*13096SJordan.Vaughan@Sun.com 				 */
209*13096SJordan.Vaughan@Sun.com 				if (mdb_readstr(subsys_name,
210*13096SJordan.Vaughan@Sun.com 				    sizeof (subsys_name),
211*13096SJordan.Vaughan@Sun.com 				    (uintptr_t)zone_ref_subsys_names[n]) ==
212*13096SJordan.Vaughan@Sun.com 				    -1) {
213*13096SJordan.Vaughan@Sun.com 					mdb_warn("unable to read subsystem name"
214*13096SJordan.Vaughan@Sun.com 					    " from zone_ref_subsys_names[%u]",
215*13096SJordan.Vaughan@Sun.com 					    n);
216*13096SJordan.Vaughan@Sun.com 					return (DCMD_ERR);
217*13096SJordan.Vaughan@Sun.com 				}
218*13096SJordan.Vaughan@Sun.com 				mdb_printf("%15s: %10u\n", subsys_name,
219*13096SJordan.Vaughan@Sun.com 				    zn.zone_subsys_ref[n]);
220*13096SJordan.Vaughan@Sun.com 			}
221*13096SJordan.Vaughan@Sun.com 			mdb_dec_indent(7);
222*13096SJordan.Vaughan@Sun.com 		}
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 	return (DCMD_OK);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate int
zone_walk_init(mdb_walk_state_t * wsp)2280Sstevel@tonic-gate zone_walk_init(mdb_walk_state_t *wsp)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate 	GElf_Sym sym;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2330Sstevel@tonic-gate 		if (mdb_lookup_by_name("zone_active", &sym) == -1) {
2340Sstevel@tonic-gate 			mdb_warn("failed to find 'zone_active'");
2350Sstevel@tonic-gate 			return (WALK_ERR);
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)sym.st_value;
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 	if (mdb_layered_walk("list", wsp) == -1) {
2400Sstevel@tonic-gate 		mdb_warn("couldn't walk 'list'");
2410Sstevel@tonic-gate 		return (WALK_ERR);
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 	return (WALK_NEXT);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate int
zone_walk_step(mdb_walk_state_t * wsp)2470Sstevel@tonic-gate zone_walk_step(mdb_walk_state_t *wsp)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
2508111SJordan.Vaughan@Sun.com 	    wsp->walk_cbdata));
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate int
zsd_walk_init(mdb_walk_state_t * wsp)2540Sstevel@tonic-gate zsd_walk_init(mdb_walk_state_t *wsp)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2570Sstevel@tonic-gate 		mdb_warn("global walk not supported\n");
2580Sstevel@tonic-gate 		return (WALK_ERR);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 	wsp->walk_addr += offsetof(struct zone, zone_zsd);
2610Sstevel@tonic-gate 	if (mdb_layered_walk("list", wsp) == -1) {
2620Sstevel@tonic-gate 		mdb_warn("couldn't walk 'list'");
2630Sstevel@tonic-gate 		return (WALK_ERR);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 	return (WALK_NEXT);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate int
zsd_walk_step(mdb_walk_state_t * wsp)2690Sstevel@tonic-gate zsd_walk_step(mdb_walk_state_t *wsp)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
2728111SJordan.Vaughan@Sun.com 	    wsp->walk_cbdata));
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2758111SJordan.Vaughan@Sun.com /*
2768111SJordan.Vaughan@Sun.com  * Helper structure used when walking ZSD entries via zsd().
2778111SJordan.Vaughan@Sun.com  */
2780Sstevel@tonic-gate struct zsd_cb_data {
2798111SJordan.Vaughan@Sun.com 	uint_t		keygiven;	/* Was a key specified (are we */
2808111SJordan.Vaughan@Sun.com 					/* searching for a specific ZSD */
2818111SJordan.Vaughan@Sun.com 					/* entry)? */
2828111SJordan.Vaughan@Sun.com 	zone_key_t	key;		/* Key of ZSD for which we're looking */
2838111SJordan.Vaughan@Sun.com 	uint_t		found;		/* Was the specific ZSD entry found? */
2848111SJordan.Vaughan@Sun.com 	uint_t		voptgiven;	/* Display verbose information? */
2850Sstevel@tonic-gate };
2860Sstevel@tonic-gate 
2878111SJordan.Vaughan@Sun.com /*
2888111SJordan.Vaughan@Sun.com  * Helper function for zsd() that displays information from a single ZSD struct.
2898111SJordan.Vaughan@Sun.com  * 'datap' must point to a valid zsd_cb_data struct.
2908111SJordan.Vaughan@Sun.com  */
2910Sstevel@tonic-gate /* ARGSUSED */
2920Sstevel@tonic-gate static int
zsd_print(uintptr_t addrp,const void * datap,void * privatep)2938111SJordan.Vaughan@Sun.com zsd_print(uintptr_t addrp, const void * datap, void * privatep)
2940Sstevel@tonic-gate {
2958111SJordan.Vaughan@Sun.com 	struct zsd_entry entry;
2968111SJordan.Vaughan@Sun.com 	struct zsd_cb_data *cbdp;
2970Sstevel@tonic-gate 
2988111SJordan.Vaughan@Sun.com 	if (mdb_vread(&entry, sizeof (entry), addrp) == -1) {
2998111SJordan.Vaughan@Sun.com 		mdb_warn("couldn't read zsd_entry at %p", addrp);
3000Sstevel@tonic-gate 		return (WALK_ERR);
3010Sstevel@tonic-gate 	}
3028111SJordan.Vaughan@Sun.com 	cbdp = (struct zsd_cb_data *)privatep;
3038111SJordan.Vaughan@Sun.com 
3048111SJordan.Vaughan@Sun.com 	/*
3058111SJordan.Vaughan@Sun.com 	 * Are we looking for a single entry specified by a key?  Then make sure
3068111SJordan.Vaughan@Sun.com 	 * that the current ZSD's key is what we're looking for.
3078111SJordan.Vaughan@Sun.com 	 */
3088111SJordan.Vaughan@Sun.com 	if (cbdp->keygiven == TRUE && cbdp->key != entry.zsd_key)
3090Sstevel@tonic-gate 		return (WALK_NEXT);
3108111SJordan.Vaughan@Sun.com 
3118111SJordan.Vaughan@Sun.com 	mdb_printf("%?x %0?p %8x\n", entry.zsd_key, entry.zsd_data,
3128111SJordan.Vaughan@Sun.com 	    entry.zsd_flags);
3138111SJordan.Vaughan@Sun.com 	if (cbdp->voptgiven == TRUE)
3148111SJordan.Vaughan@Sun.com 		mdb_printf("    Create CB:   %a\n    Shutdown CB: %a\n"
3158111SJordan.Vaughan@Sun.com 		    "    Destroy CB:  %a\n", entry.zsd_create,
3168111SJordan.Vaughan@Sun.com 		    entry.zsd_shutdown, entry.zsd_destroy);
3178111SJordan.Vaughan@Sun.com 	if (cbdp->keygiven == TRUE) {
3188111SJordan.Vaughan@Sun.com 		cbdp->found = TRUE;
3198111SJordan.Vaughan@Sun.com 		return (WALK_DONE);
3208111SJordan.Vaughan@Sun.com 	}
3218111SJordan.Vaughan@Sun.com 	return (WALK_NEXT);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate int
zsd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3250Sstevel@tonic-gate zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate 	zone_t zone;
3288111SJordan.Vaughan@Sun.com 	const mdb_arg_t *argp;
3298111SJordan.Vaughan@Sun.com 	int argcindex;
3300Sstevel@tonic-gate 	struct zsd_cb_data cbd;
3318111SJordan.Vaughan@Sun.com 	char name[ZONE_NAMELEN];
3328111SJordan.Vaughan@Sun.com 	int len;
3330Sstevel@tonic-gate 
3348111SJordan.Vaughan@Sun.com 	/*
3358111SJordan.Vaughan@Sun.com 	 * Walk all zones if necessary.
3368111SJordan.Vaughan@Sun.com 	 */
3378111SJordan.Vaughan@Sun.com 	if (argc > 2)
3388111SJordan.Vaughan@Sun.com 		return (DCMD_USAGE);
3390Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
3408111SJordan.Vaughan@Sun.com 		if (mdb_walk_dcmd("zone", "zsd", argc, argv) == -1) {
3418111SJordan.Vaughan@Sun.com 			mdb_warn("failed to walk zone\n");
3428111SJordan.Vaughan@Sun.com 			return (DCMD_ERR);
3438111SJordan.Vaughan@Sun.com 		}
3448111SJordan.Vaughan@Sun.com 		return (DCMD_OK);
3458111SJordan.Vaughan@Sun.com 	}
3468111SJordan.Vaughan@Sun.com 
3478111SJordan.Vaughan@Sun.com 	/*
3488111SJordan.Vaughan@Sun.com 	 * Make sure a zone_t can be read from the specified address.
3498111SJordan.Vaughan@Sun.com 	 */
3508111SJordan.Vaughan@Sun.com 	if (mdb_vread(&zone, sizeof (zone), addr) == -1) {
3518111SJordan.Vaughan@Sun.com 		mdb_warn("couldn't read zone_t at %p", (void *)addr);
3520Sstevel@tonic-gate 		return (DCMD_ERR);
3530Sstevel@tonic-gate 	}
3548111SJordan.Vaughan@Sun.com 
3558111SJordan.Vaughan@Sun.com 	/*
3568111SJordan.Vaughan@Sun.com 	 * Get the optional arguments (key or -v or both).  Note that
3578111SJordan.Vaughan@Sun.com 	 * mdb_getopts() will not parse a key argument because it is not
3588111SJordan.Vaughan@Sun.com 	 * preceded by an option letter.  We'll get around this by requiring
3598111SJordan.Vaughan@Sun.com 	 * that all options precede the optional key argument.
3608111SJordan.Vaughan@Sun.com 	 */
3618111SJordan.Vaughan@Sun.com 	cbd.keygiven = FALSE;
3628111SJordan.Vaughan@Sun.com 	cbd.voptgiven = FALSE;
3638111SJordan.Vaughan@Sun.com 	if (argc > 0 && (argcindex = mdb_getopts(argc, argv, 'v',
3648111SJordan.Vaughan@Sun.com 	    MDB_OPT_SETBITS, TRUE, &cbd.voptgiven, NULL)) != argc) {
3658111SJordan.Vaughan@Sun.com 		/*
3668111SJordan.Vaughan@Sun.com 		 * No options may appear after the key.
3678111SJordan.Vaughan@Sun.com 		 */
3688111SJordan.Vaughan@Sun.com 		if (argcindex != argc - 1)
3698111SJordan.Vaughan@Sun.com 			return (DCMD_USAGE);
3708111SJordan.Vaughan@Sun.com 
3718111SJordan.Vaughan@Sun.com 		/*
3728111SJordan.Vaughan@Sun.com 		 * The missed argument should be a key.
3738111SJordan.Vaughan@Sun.com 		 */
3748111SJordan.Vaughan@Sun.com 		argp = &argv[argcindex];
3758111SJordan.Vaughan@Sun.com 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
3768111SJordan.Vaughan@Sun.com 			cbd.key = argp->a_un.a_val;
3778111SJordan.Vaughan@Sun.com 		else
3788111SJordan.Vaughan@Sun.com 			cbd.key = mdb_strtoull(argp->a_un.a_str);
3798111SJordan.Vaughan@Sun.com 		cbd.keygiven = TRUE;
3808111SJordan.Vaughan@Sun.com 		cbd.found = FALSE;
3818111SJordan.Vaughan@Sun.com 	}
3828111SJordan.Vaughan@Sun.com 
3838111SJordan.Vaughan@Sun.com 	/*
3848111SJordan.Vaughan@Sun.com 	 * Prepare to output the specified zone's ZSD information.
3858111SJordan.Vaughan@Sun.com 	 */
3868111SJordan.Vaughan@Sun.com 	if (DCMD_HDRSPEC(flags))
3878111SJordan.Vaughan@Sun.com 		mdb_printf("%<u>%-20s %?s %?s %8s%</u>\n", "ZONE", "KEY",
3888111SJordan.Vaughan@Sun.com 		    "VALUE", "FLAGS");
3898111SJordan.Vaughan@Sun.com 	len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zone.zone_name);
3908111SJordan.Vaughan@Sun.com 	if (len > 0) {
3918111SJordan.Vaughan@Sun.com 		if (len == ZONE_NAMELEN)
3928111SJordan.Vaughan@Sun.com 			(void) strcpy(&name[len - 4], "...");
3938111SJordan.Vaughan@Sun.com 	} else {
3948111SJordan.Vaughan@Sun.com 		(void) strcpy(name, "??");
3958111SJordan.Vaughan@Sun.com 	}
3968111SJordan.Vaughan@Sun.com 	mdb_printf("%-20s ", name);
3978111SJordan.Vaughan@Sun.com 
3988111SJordan.Vaughan@Sun.com 	/*
3998111SJordan.Vaughan@Sun.com 	 * Display the requested ZSD entries.
4008111SJordan.Vaughan@Sun.com 	 */
4018111SJordan.Vaughan@Sun.com 	mdb_inc_indent(21);
4028111SJordan.Vaughan@Sun.com 	if (mdb_pwalk("zsd", zsd_print, &cbd, addr) != 0) {
4038111SJordan.Vaughan@Sun.com 		mdb_warn("failed to walk zsd\n");
4048111SJordan.Vaughan@Sun.com 		mdb_dec_indent(21);
4050Sstevel@tonic-gate 		return (DCMD_ERR);
4060Sstevel@tonic-gate 	}
4078111SJordan.Vaughan@Sun.com 	if (cbd.keygiven == TRUE && cbd.found == FALSE) {
4088111SJordan.Vaughan@Sun.com 		mdb_printf("no corresponding ZSD entry found\n");
4098111SJordan.Vaughan@Sun.com 		mdb_dec_indent(21);
4100Sstevel@tonic-gate 		return (DCMD_ERR);
4110Sstevel@tonic-gate 	}
4128111SJordan.Vaughan@Sun.com 	mdb_dec_indent(21);
4130Sstevel@tonic-gate 	return (DCMD_OK);
4140Sstevel@tonic-gate }
415