Home | History | Annotate | Download | only in util
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include <stdio.h>
     28 #include <errno.h>
     29 #include <unistd.h>
     30 #include <string.h>
     31 
     32 #include <meta.h>
     33 #include <sys/lvm/md_mddb.h>
     34 #include <sdssc.h>
     35 
     36 /*
     37  * print metadevice status
     38  */
     39 
     40 
     41 #define	MD_PROBE_OPEN_T "probe open test"
     42 
     43 /* used to keep track of the softparts on the same underlying device */
     44 struct sp_base_list {
     45 	struct sp_base_list	*next;
     46 	char			*base;
     47 };
     48 
     49 /*
     50  * Function prototypes
     51  */
     52 static void probe_all_devs(mdsetname_t *sp);
     53 
     54 static int print_devid(mdsetname_t *sp, mdnamelist_t *nlp, FILE *fp,
     55     md_error_t   *ep);
     56 
     57 static md_common_t	*get_concise_unit(mdsetname_t *sp, mdname_t *np,
     58 			    md_error_t *ep);
     59 static void	print_all_sets(mdprtopts_t options, int concise_flag,
     60 		    int quiet_flg);
     61 static void	print_specific_set(mdsetname_t *sp, mdprtopts_t options,
     62 		    int concise_flag, int quiet_flg);
     63 static void	print_concise_diskset(mdsetname_t *sp);
     64 static void	print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl,
     65 		    char mtype);
     66 static void	print_concise_md(int indent, mdsetname_t *sp, mdname_t *np);
     67 static void	print_concise_mirror(int indent, mdsetname_t *sp,
     68 		    md_mirror_t *mirror);
     69 static void	print_concise_raid(int indent, mdsetname_t *sp,
     70 		    md_raid_t *raid);
     71 static void	print_concise_stripe(int indent, mdsetname_t *sp,
     72 		    md_stripe_t *stripe);
     73 static void	print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part);
     74 static void	print_concise_trans(int indent, mdsetname_t *sp,
     75 		    md_trans_t *trans);
     76 static void	free_names(mdnamelist_t **nlp);
     77 static char	*get_sm_state(md_mirror_t *mirror, int i,
     78 		    md_status_t mirror_status, uint_t tstate);
     79 static char	*get_raid_col_state(md_raidcol_t *colp, uint_t tstate);
     80 static char	*get_stripe_state(md_comp_t *mdcp, uint_t tstate);
     81 static char	*get_hs_state(md_hs_t *hsp);
     82 static struct sp_base_list *sp_add_done(md_sp_t *part, struct sp_base_list *lp);
     83 static int	sp_done(md_sp_t *part, struct sp_base_list *lp);
     84 static int	sp_match(md_sp_t *part, struct sp_base_list *lp);
     85 static void	sp_free_list(struct sp_base_list *lp);
     86 
     87 
     88 /*
     89  * print named hotspare pool or metadevice
     90  */
     91 static int
     92 print_name(
     93 	mdsetname_t	**spp,
     94 	char		*uname,
     95 	mdnamelist_t	**nlistpp,
     96 	char		*fname,
     97 	FILE		*fp,
     98 	mdprtopts_t	options,
     99 	int		*meta_print_trans_msgp,
    100 	mdnamelist_t	**lognlpp,
    101 	md_error_t	*ep
    102 )
    103 {
    104 	mdname_t	*namep;
    105 	char		*miscname;
    106 
    107 	/* recurse */
    108 	options |= PRINT_SUBDEVS;
    109 
    110 	/* hotspare pool */
    111 	if (is_existing_hsp(*spp, uname)) {
    112 		mdhspname_t	*hspnamep;
    113 
    114 		/* get hotsparepool */
    115 		if ((hspnamep = metahspname(spp, uname, ep)) == NULL)
    116 			return (-1);
    117 
    118 		/* check for ownership */
    119 		assert(*spp != NULL);
    120 		if (meta_check_ownership(*spp, ep) != 0)
    121 			return (-1);
    122 
    123 		/* print hotspare pool */
    124 		return (meta_hsp_print(*spp, hspnamep, lognlpp, fname, fp,
    125 		    options, ep));
    126 	}
    127 
    128 	/* get metadevice */
    129 	if (((namep = metaname(spp, uname, META_DEVICE, ep)) == NULL) ||
    130 	    (metachkmeta(namep, ep) != 0))
    131 		return (-1);
    132 
    133 	/* check for ownership */
    134 	assert(*spp != NULL);
    135 	if (meta_check_ownership(*spp, ep) != 0)
    136 		return (-1);
    137 
    138 	if ((miscname = metagetmiscname(namep, ep)) != NULL) {
    139 		if (strcmp(miscname, MD_TRANS) == 0) {
    140 			*meta_print_trans_msgp = 1;
    141 		}
    142 	}
    143 
    144 	/* print metadevice */
    145 	return (meta_print_name(*spp, namep, nlistpp, fname, fp, options,
    146 	    lognlpp, ep));
    147 }
    148 
    149 /*
    150  * print the per set flags
    151  */
    152 /*ARGSUSED*/
    153 static int
    154 print_setstat(
    155 	mdsetname_t		**spp,
    156 	char			*fname,
    157 	FILE			*fp,
    158 	mdprtopts_t		options,
    159 	md_error_t		*ep
    160 )
    161 {
    162 	int			rval = -1;
    163 	char			*cname = NULL;
    164 	char			*cp = NULL;
    165 	md_gs_stat_parm_t	gsp;
    166 
    167 
    168 	if (fname != NULL && strchr(fname, '/') != NULL) {
    169 		/* get the canonical name */
    170 		cname = meta_name_getname(spp, fname, META_DEVICE, ep);
    171 		if (cname == NULL)
    172 			return (-1);
    173 		Free(cname);
    174 	}
    175 
    176 	if ((cp = getenv("MD_DEBUG")) == NULL)
    177 		return (0);
    178 
    179 	if (strstr(cp, "SETINFO") == NULL)
    180 		return (0);
    181 
    182 	(void) memset(&gsp, '\0', sizeof (md_gs_stat_parm_t));
    183 	gsp.gs_setno = (*spp)->setno;
    184 
    185 	if (metaioctl(MD_GET_SETSTAT, &gsp, &gsp.gs_mde, NULL) != 0)
    186 		return (mdstealerror(ep, &gsp.gs_mde));
    187 
    188 	if (fprintf(fp, "Status for set %d = ", gsp.gs_setno) == EOF)
    189 		goto out;
    190 
    191 	if (meta_prbits(fp, NULL, gsp.gs_status, MD_SET_STAT_BITS) == EOF)
    192 		goto out;
    193 
    194 
    195 	if (fprintf(fp, "\n") == EOF)
    196 		goto out;
    197 
    198 	/* success */
    199 	rval = 0;
    200 
    201 	/* cleanup, return error */
    202 out:
    203 	if (rval != 0)
    204 		(void) mdsyserror(ep, errno, fname);
    205 
    206 	return (rval);
    207 }
    208 
    209 /*
    210  * check_replica_state:
    211  * 	If the replica state is stale or the set has been halted
    212  * 	this routine returns an error.
    213  */
    214 static int
    215 check_replica_state(mdsetname_t *sp, md_error_t *ep)
    216 {
    217 	mddb_config_t	c;
    218 
    219 	(void) memset(&c, 0, sizeof (c));
    220 	c.c_id = 0;
    221 	c.c_setno = sp->setno;
    222 
    223 	if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) {
    224 		if (mdismddberror(&c.c_mde, MDE_DB_INVALID))
    225 			(void) mdstealerror(ep, &c.c_mde);
    226 		return (-1);
    227 	}
    228 
    229 	if (c.c_flags & MDDB_C_STALE) {
    230 		return (mdmddberror(ep, MDE_DB_STALE, NODEV32, sp->setno,
    231 		    0, NULL));
    232 	} else
    233 		return (0);
    234 }
    235 
    236 static void
    237 print_trans_msg(mdprtopts_t	options, int	meta_print_trans_msg)
    238 {
    239 	if (meta_print_trans_msg != 0) {
    240 		(void) fprintf(stderr, "\n\n");
    241 		if (options & PRINT_SHORT) {
    242 			(void) fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_MSG));
    243 			(void) fprintf(stderr,
    244 			    gettext(MD_SHORT_EOF_TRANS_WARNING));
    245 		} else {
    246 			(void) fprintf(stderr, gettext(MD_EOF_TRANS_MSG));
    247 			(void) fprintf(stderr, gettext(MD_EOF_TRANS_WARNING));
    248 		}
    249 	}
    250 }
    251 
    252 /*
    253  * print usage message
    254  *
    255  */
    256 static void
    257 usage(
    258 	mdsetname_t	*sp,
    259 	int		eval
    260 )
    261 {
    262 	(void) fprintf(stderr, gettext("\
    263 usage:	%s [-s setname] [-a][-c][-B][-D][-r][-i][-p] [-t] [metadevice...]\n"),
    264 	    myname);
    265 	md_exit(sp, eval);
    266 }
    267 
    268 /*
    269  * mainline. crack command line arguments.
    270  */
    271 int
    272 main(
    273 	int	argc,
    274 	char	*argv[]
    275 )
    276 {
    277 	char		*sname = MD_LOCAL_NAME;
    278 	mdsetname_t	*sp = NULL;
    279 	mdprtopts_t	options = PRINT_HEADER | PRINT_DEVID | PRINT_FAST;
    280 	int		c;
    281 	char		*p;
    282 	md_error_t	status = mdnullerror;
    283 	md_error_t	*ep = &status;
    284 	int		eval = 0;
    285 	int		inquire = 0;
    286 	int		quiet_flg = 0;
    287 	int		set_flg = 0;
    288 	int		error;
    289 	int		all_sets_flag = 0;
    290 	int		concise_flag = 0;
    291 	mdnamelist_t	*nlistp = NULL;
    292 	mdname_t		*namep;
    293 	int		devcnt = 0;
    294 	mdnamelist_t	*lognlp = NULL;
    295 	uint_t hsi;
    296 	int		meta_print_trans_msg = 0;
    297 
    298 	/*
    299 	 * Get the locale set up before calling any other routines
    300 	 * with messages to ouput.  Just in case we're not in a build
    301 	 * environment, make sure that TEXT_DOMAIN gets set to
    302 	 * something.
    303 	 */
    304 #if !defined(TEXT_DOMAIN)
    305 #define	TEXT_DOMAIN "SYS_TEST"
    306 #endif
    307 	(void) setlocale(LC_ALL, "");
    308 	(void) textdomain(TEXT_DOMAIN);
    309 
    310 	if (sdssc_bind_library() == SDSSC_OKAY)
    311 		if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
    312 		    &error) == SDSSC_PROXY_DONE)
    313 			exit(error);
    314 
    315 	/* initialize */
    316 	if (md_init(argc, argv, 0, 1, ep) != 0) {
    317 		mde_perror(ep, "");
    318 		md_exit(sp, 1);
    319 	}
    320 
    321 	/* parse arguments */
    322 	optind = 1;
    323 	opterr = 1;
    324 	while ((c = getopt(argc, argv, "acSs:hpBDrtiq?")) != -1) {
    325 		switch (c) {
    326 		case 'a':
    327 			all_sets_flag++;
    328 			break;
    329 
    330 		case 'c':
    331 			concise_flag++;
    332 			quiet_flg++;
    333 			break;
    334 
    335 		case 'S':
    336 			options |= PRINT_SETSTAT_ONLY;
    337 			break;
    338 
    339 		case 's':
    340 			sname = optarg;
    341 			set_flg++;
    342 			break;
    343 
    344 		case 'h':
    345 			usage(sp, 0);
    346 			break;
    347 
    348 		case 'p':
    349 			options |= PRINT_SHORT;
    350 			options &= ~PRINT_DEVID;
    351 			break;
    352 
    353 		case 't':
    354 			options |= PRINT_TIMES;
    355 			break;
    356 
    357 		case 'i':
    358 			inquire++;
    359 			break;
    360 
    361 		case 'B':
    362 			options |= PRINT_LARGEDEVICES;
    363 			break;
    364 		case 'D':
    365 			options |= PRINT_FN;
    366 			break;
    367 		case 'r':		/* defunct option */
    368 			break;
    369 		case 'q':
    370 			quiet_flg++;
    371 			break;
    372 		case '?':
    373 			if (optopt == '?')
    374 				usage(sp, 0);
    375 			/*FALLTHROUGH*/
    376 		default:
    377 			usage(sp, 1);
    378 			break;
    379 		}
    380 	}
    381 	argc -= optind;
    382 	argv += optind;
    383 
    384 	if (all_sets_flag && set_flg) {
    385 		(void) fprintf(stderr, gettext("metastat: "
    386 		    "incompatible options: -a and -s\n"));
    387 		usage(sp, 1);
    388 	}
    389 
    390 	/* get set context */
    391 	if ((sp = metasetname(sname, ep)) == NULL) {
    392 		mde_perror(ep, "");
    393 		md_exit(sp, 1);
    394 	}
    395 
    396 	/* make sure that the mddb is not stale. Else print a warning */
    397 
    398 	if (check_replica_state(sp, ep)) {
    399 		if (mdismddberror(ep, MDE_DB_STALE)) {
    400 			(void) fprintf(stdout, gettext(
    401 			    "****\nWARNING: Stale "
    402 			    "state database replicas. Metastat output "
    403 			    "may be inaccurate.\n****\n\n"));
    404 		}
    405 	}
    406 
    407 	/* if inquire is set. We probe first */
    408 	if (inquire) {
    409 		if (geteuid() != 0) {
    410 			(void) fprintf(stderr, gettext("metastat: -i "
    411 			    "option requires super-user privilages\n"));
    412 			md_exit(sp, 1);
    413 		}
    414 		probe_all_devs(sp);
    415 	}
    416 	/* print debug stuff */
    417 	if (((p = getenv("MD_DEBUG")) != NULL) &&
    418 	    (strstr(p, "STAT") != NULL)) {
    419 		options |= (PRINT_SETSTAT | PRINT_DEBUG | PRINT_TIMES);
    420 	}
    421 
    422 	if ((options & PRINT_SETSTAT) || (options & PRINT_SETSTAT_ONLY)) {
    423 		if (print_setstat(&sp, argv[0], stdout, options, ep)) {
    424 			mde_perror(ep, "");
    425 			md_exit(sp, 1);
    426 		}
    427 		if (options & PRINT_SETSTAT_ONLY)
    428 			md_exit(sp, 0);
    429 	}
    430 
    431 	/* status all devices */
    432 	if (argc == 0) {
    433 		if (all_sets_flag) {
    434 			print_all_sets(options, concise_flag, quiet_flg);
    435 		} else {
    436 			print_specific_set(sp, options, concise_flag,
    437 			    quiet_flg);
    438 		}
    439 
    440 		if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
    441 			mde_perror(ep, "");
    442 			md_exit(sp, 1);
    443 		}
    444 
    445 		/* success */
    446 		md_exit(sp, 0);
    447 	}
    448 	/* print named device types */
    449 	while (devcnt < argc) {
    450 		char	*uname = argv[devcnt];
    451 		char	*cname = NULL;
    452 
    453 		/* get the canonical name */
    454 		cname = meta_name_getname(&sp, uname, META_DEVICE, ep);
    455 		if (cname == NULL) {
    456 			/* already printed the error */
    457 			mdclrerror(ep);
    458 			eval = 1;
    459 			++devcnt;
    460 			continue;
    461 		}
    462 
    463 		if (concise_flag) {
    464 			mdname_t *np;
    465 
    466 			np = metaname(&sp, cname, META_DEVICE, ep);
    467 			if (np == NULL) {
    468 				mde_perror(ep, "");
    469 				mdclrerror(ep);
    470 				eval = 1;
    471 			} else {
    472 				print_concise_md(0, sp, np);
    473 			}
    474 
    475 		} else {
    476 			if (print_name(&sp, cname, &nlistp, NULL, stdout,
    477 			    options, &meta_print_trans_msg, &lognlp, ep) != 0) {
    478 				mde_perror(ep, "");
    479 				mdclrerror(ep);
    480 				eval = 1;
    481 			}
    482 		}
    483 		Free(cname);
    484 		++devcnt;
    485 	}
    486 
    487 	/* print metadevice & relocation device id */
    488 	if ((options & PRINT_DEVID) && (eval != 1) && !quiet_flg) {
    489 		devcnt = 0;
    490 
    491 		while (devcnt < argc) {
    492 			char	*uname = argv[devcnt];
    493 			char	*cname = NULL;
    494 
    495 			/* get the canonical name */
    496 			cname = meta_name_getname(&sp, uname, META_DEVICE, ep);
    497 			if (cname == NULL) {
    498 				mde_perror(ep, "");
    499 				mdclrerror(ep);
    500 				++devcnt;
    501 				continue;
    502 			}
    503 
    504 			/* hotspare pools */
    505 			if (is_existing_hsp(sp, cname)) {
    506 				mdhspname_t	*hspnamep;
    507 				md_hsp_t	*hsp;
    508 
    509 				/* get hotsparepool */
    510 				if ((hspnamep = metahspname(&sp, cname,
    511 				    ep)) == NULL)
    512 					eval = 1;
    513 
    514 				if ((hsp = meta_get_hsp(sp, hspnamep,
    515 				    ep)) == NULL)
    516 					eval = 1;
    517 
    518 				for (hsi = 0;
    519 				    hsi < hsp->hotspares.hotspares_len;
    520 				    hsi++) {
    521 
    522 					namep = hsp->hotspares.
    523 					    hotspares_val[hsi].hsnamep;
    524 
    525 					if (!(options &
    526 					    (PRINT_LARGEDEVICES | PRINT_FN))) {
    527 						/* meta_getdevs populates the */
    528 						/* nlistp structure for use   */
    529 						if (meta_getdevs(sp, namep,
    530 						    &nlistp, ep) != 0)
    531 							eval =  1;
    532 					}
    533 
    534 				}
    535 
    536 			} else {
    537 
    538 				/* get metadevice */
    539 				if (((namep = metaname(&sp, cname,
    540 				    META_DEVICE, ep)) == NULL) ||
    541 				    (metachkmeta(namep, ep) != 0))
    542 					eval = 1;
    543 
    544 				if (!(options &
    545 				    (PRINT_LARGEDEVICES | PRINT_FN))) {
    546 					/* meta_getdevs populates the	*/
    547 					/* nlistp structure for use 	*/
    548 					if (meta_getdevs(sp, namep, &nlistp, ep)
    549 					    != 0)
    550 						eval =  1;
    551 				}
    552 			}
    553 			Free(cname);
    554 			++devcnt;
    555 		}
    556 		if (print_devid(sp, nlistp, stdout, ep) != 0)
    557 			eval =  1;
    558 
    559 
    560 	}
    561 
    562 	print_trans_msg(options, meta_print_trans_msg);
    563 
    564 	if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
    565 		mde_perror(ep, "");
    566 		md_exit(sp, 1);
    567 	}
    568 
    569 	/* return success */
    570 	md_exit(sp, eval);
    571 	/*NOTREACHED*/
    572 	return (eval);
    573 }
    574 
    575 static void
    576 print_all_sets(mdprtopts_t options, int concise_flag, int quiet_flg)
    577 {
    578 	uint_t		max_sets;
    579 	md_error_t	error = mdnullerror;
    580 	int		i;
    581 
    582 	if ((max_sets = get_max_sets(&error)) == 0) {
    583 		return;
    584 	}
    585 
    586 	if (!mdisok(&error)) {
    587 		mdclrerror(&error);
    588 		return;
    589 	}
    590 
    591 	/* for each possible set number, see if we really have a diskset */
    592 	for (i = 0; i < max_sets; i++) {
    593 		mdsetname_t		*sp;
    594 
    595 		if ((sp = metasetnosetname(i, &error)) == NULL) {
    596 			if (!mdisok(&error) &&
    597 			    mdisrpcerror(&error, RPC_PROGNOTREGISTERED)) {
    598 			/* metad rpc program not registered - no metasets */
    599 				break;
    600 			}
    601 
    602 			mdclrerror(&error);
    603 			continue;
    604 		}
    605 		mdclrerror(&error);
    606 
    607 		if (meta_check_ownership(sp, &error) == 0) {
    608 			/* we own the set, so we can print the metadevices */
    609 			print_specific_set(sp, options, concise_flag,
    610 			    quiet_flg);
    611 			(void) printf("\n");
    612 		}
    613 
    614 		metaflushsetname(sp);
    615 	}
    616 }
    617 
    618 static void
    619 print_specific_set(mdsetname_t *sp, mdprtopts_t options, int concise_flag,
    620 	int quiet_flg)
    621 {
    622 	md_error_t	status = mdnullerror;
    623 	md_error_t	*ep = &status;
    624 	int		meta_print_trans_msg = 0;
    625 
    626 	/* check for ownership */
    627 	assert(sp != NULL);
    628 	if (meta_check_ownership(sp, ep) != 0) {
    629 		mde_perror(ep, "");
    630 		md_exit(sp, 1);
    631 	}
    632 
    633 	if (concise_flag) {
    634 		print_concise_diskset(sp);
    635 
    636 	} else {
    637 		mdnamelist_t	*nlistp = NULL;
    638 
    639 		/* status devices */
    640 		if (meta_print_all(sp, NULL, &nlistp, stdout, options,
    641 		    &meta_print_trans_msg, ep) != 0) {
    642 			mde_perror(ep, "");
    643 			md_exit(sp, 1);
    644 		}
    645 
    646 		/* print relocation device id on all dev's */
    647 		if ((options & PRINT_DEVID) && !quiet_flg) {
    648 			/*
    649 			 * Ignore return value from meta_getalldevs since
    650 			 * it will return a failure if even one device cannot
    651 			 * be found - which could occur in the case of device
    652 			 * failure or a device being powered off during
    653 			 * upgrade.  Even if meta_getalldevs fails, the
    654 			 * data in nlistp is still valid.
    655 			 */
    656 			if (!(options & (PRINT_LARGEDEVICES | PRINT_FN))) {
    657 				(void) meta_getalldevs(sp, &nlistp, 0, ep);
    658 			}
    659 			if (nlistp != NULL) {
    660 				if (print_devid(sp, nlistp, stdout, ep) != 0) {
    661 					mde_perror(ep, "");
    662 					md_exit(sp, 1);
    663 				}
    664 			}
    665 		}
    666 	}
    667 
    668 	print_trans_msg(options, meta_print_trans_msg);
    669 }
    670 
    671 /*
    672  * print_devid prints out cxtxdx and devid for devices passed in a
    673  * mdnamelist_t structure
    674  */
    675 static int
    676 print_devid(
    677 	mdsetname_t  *sp,
    678 	mdnamelist_t *nlp,
    679 	FILE		 *fp,
    680 	md_error_t   *ep
    681 )
    682 {
    683 	int 			retval = 0;
    684 	mdnamelist_t		*onlp = NULL;
    685 	mddevid_t 		*ldevidp = NULL;
    686 	mddevid_t		*nextp;
    687 
    688 	/* make a non-duplicate list of nlp */
    689 	for (onlp = nlp; (onlp != NULL); onlp = onlp->next) {
    690 		meta_create_non_dup_list(onlp->namep, &ldevidp);
    691 	}
    692 
    693 	retval = meta_print_devid(sp, fp, ldevidp, ep);
    694 
    695 	/* cleanup */
    696 	for (nextp = ldevidp; nextp != NULL; ldevidp = nextp) {
    697 		Free(ldevidp->ctdname);
    698 		nextp = ldevidp->next;
    699 		Free(ldevidp);
    700 	}
    701 
    702 	return (retval);
    703 }
    704 
    705 /*
    706  * probedev issues ioctls for all the metadevices
    707  */
    708 
    709 
    710 
    711 
    712 /*
    713  * Failure return's a 1
    714  */
    715 int
    716 hotspare_ok(char *bname)
    717 {
    718 	int fd;
    719 	char buf[512];
    720 
    721 	if ((fd = open(bname, O_RDONLY)) < 0)
    722 		return (0);
    723 	if (read(fd, buf, sizeof (buf)) < 0) {
    724 		(void) close(fd);
    725 		return (0);
    726 	}
    727 	(void) close(fd);
    728 	return (1);
    729 }
    730 
    731 void
    732 delete_hotspares_impl(mdsetname_t *sp, mdhspname_t *hspnp, md_hsp_t *hspp)
    733 {
    734 	md_hs_t *hsp;
    735 	uint_t		hsi;
    736 	char    *bname;
    737 	md_error_t e = mdnullerror;
    738 	int deleted_hs = 0;
    739 
    740 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
    741 		mdnamelist_t *nlp;
    742 
    743 		hsp = &hspp->hotspares.hotspares_val[hsi];
    744 		bname = hsp->hsnamep->bname;
    745 		nlp = NULL;
    746 		(void) metanamelist_append(&nlp, hsp->hsnamep);
    747 		/* print hotspare */
    748 		if (hsp->state == HSS_AVAILABLE) {
    749 			if (hotspare_ok(bname))
    750 				continue;
    751 
    752 			(void) fprintf(stderr,
    753 			    "NOTICE: Hotspare %s in %s has failed.\n"
    754 			    "\tDeleting %s since it not in use\n\n",
    755 			    bname, hspnp->hspname, bname);
    756 
    757 			if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) {
    758 				mde_perror(&e, "");
    759 				mdclrerror(&e);
    760 			} else {
    761 				deleted_hs++;
    762 			}
    763 		}
    764 	}
    765 }
    766 
    767 
    768 
    769 /*
    770  * Generic routine to issue ioctls
    771  */
    772 
    773 void
    774 md_setprobetest(md_probedev_t *iocp)
    775 {
    776 	(void) strcpy(iocp->test_name, MD_PROBE_OPEN_T);
    777 }
    778 
    779 int
    780 md_probe_ioctl(mdsetname_t *sp, mdnamelist_t *nlp, int ndevs, char *drvname)
    781 {
    782 	mdnamelist_t	*p;
    783 	mdname_t	*np;
    784 	md_probedev_t	probe_ioc, *iocp;
    785 	int		i, retval = 0;
    786 	/*
    787 	 * Allocate space for all the metadevices and fill in
    788 	 * the minor numbers.
    789 	 */
    790 
    791 	(void) memset(&probe_ioc, 0, sizeof (probe_ioc));
    792 	iocp = &probe_ioc;
    793 
    794 	if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t)))
    795 	    == 0) {
    796 		perror("md_probe_ioctl: calloc");
    797 		return (-1);
    798 	}
    799 
    800 	MD_SETDRIVERNAME(iocp, drvname, sp->setno);
    801 	md_setprobetest(iocp);
    802 
    803 	iocp->nmdevs = ndevs;
    804 
    805 	for (p = nlp, i = 0; p; p = p->next, i++) {
    806 		np = p->namep;
    807 		((minor_t *)(uintptr_t)iocp->mnum_list)[i] =
    808 		    meta_getminor(np->dev);
    809 	}
    810 
    811 
    812 	if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0)
    813 			retval = -1;
    814 	Free((void *)(uintptr_t)iocp->mnum_list);
    815 	return (retval);
    816 }
    817 /*
    818  *
    819  *  - remove p from nlp list
    820  *  - put it on the toplp list.
    821  *  - update the p to the next element
    822  */
    823 
    824 void
    825 add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp, mdnamelist_t **newlpp)
    826 {
    827 	mdnamelist_t	*p, *prevp, *nlp;
    828 
    829 	p = *curpp;
    830 	prevp = *prevpp;
    831 	nlp = *newlpp;
    832 
    833 	if (prevp == p) {
    834 		/* if first element reset prevp */
    835 			prevp = p->next;
    836 			p->next = nlp;
    837 			nlp = p;
    838 			p = prevp;
    839 	} else {
    840 		prevp->next = p->next;
    841 		p->next = nlp;
    842 		nlp = p;
    843 		p = prevp->next;
    844 	}
    845 	*curpp = p;
    846 	*prevpp = prevp;
    847 	*newlpp = nlp;
    848 }
    849 /*
    850  * Scans the given list of metadeivces and returns a list of top level
    851  * metadevices.
    852  * Note: The orignal list is not valid at the end and is set to NULL.
    853  */
    854 
    855 int
    856 get_toplevel_mds(mdsetname_t *sp, mdnamelist_t **lpp,
    857 			mdnamelist_t **top_pp)
    858 {
    859 	mdnamelist_t	*p, *prevp, *toplp;
    860 	int		ntopmd;
    861 	md_common_t	*mdp;
    862 	md_error_t	e = mdnullerror;
    863 
    864 	ntopmd = 0;
    865 	prevp = p = *lpp;
    866 	toplp = NULL;
    867 
    868 	while (p) {
    869 		if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) {
    870 				prevp = p;
    871 				p = p->next;
    872 				continue;
    873 		}
    874 
    875 		if (mdp->parent == MD_NO_PARENT) {
    876 			/* increment the top level md count. */
    877 			ntopmd++;
    878 			add_to_list(&p, &prevp, &toplp);
    879 		} else {
    880 			prevp = p;
    881 			p = p->next;
    882 		}
    883 	}
    884 	*lpp = NULL;
    885 	*top_pp = toplp;
    886 
    887 	return (ntopmd);
    888 }
    889 
    890 int
    891 get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist,
    892 					char *dev_type)
    893 {
    894 	mdnamelist_t *np, *prevp;
    895 	md_error_t	e = mdnullerror;
    896 	char		*type_name;
    897 	int		i = 0;
    898 
    899 	prevp = np = *transdevlist;
    900 	while (np) {
    901 		if ((type_name = metagetmiscname(np->namep, &e)) == NULL) {
    902 			*devlist = NULL;
    903 			return (-1);
    904 		}
    905 		if (strcmp(type_name, dev_type) == 0) {
    906 			/* move it to the devlist */
    907 			add_to_list(&np, &prevp, devlist);
    908 			i++;
    909 		} else {
    910 			prevp = np;
    911 			np = np->next;
    912 		}
    913 	}
    914 	return (i);
    915 }
    916 
    917 
    918 mdnamelist_t *
    919 create_nlp(mdsetname_t *sp)
    920 {
    921 	mdnamelist_t *np;
    922 	md_error_t   e = mdnullerror;
    923 
    924 	if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) {
    925 		np->next = NULL;
    926 		return (np);
    927 	} else {
    928 		/* error condition below */
    929 		mde_perror(&e, "create_nlp: malloc failed\n");
    930 		md_exit(sp, 1);
    931 	}
    932 	return (0);
    933 }
    934 
    935 /*
    936  * Create a list of metadevices associated with trans. top_pp points to
    937  * this list. The number of components in the list are also returned.
    938  */
    939 int
    940 create_trans_compslist(mdsetname_t *sp, mdnamelist_t **lpp,
    941 				mdnamelist_t **top_pp)
    942 {
    943 	mdnamelist_t	*p, *tailp, *toplp, *newlp;
    944 	int		ntoptrans;
    945 	md_error_t	e = mdnullerror;
    946 	md_trans_t	*tp;
    947 
    948 	ntoptrans = 0;
    949 	p = *lpp;
    950 	tailp = toplp = NULL;
    951 	/*
    952 	 * Scan the current list of trans devices. From that
    953 	 * extract all the lower level metadevices and put them on
    954 	 * toplp list.
    955 	 */
    956 
    957 	while (p) {
    958 		if (tp = meta_get_trans(sp, p->namep, &e)) {
    959 			/*
    960 			 * Check the master and log devices to see if they
    961 			 * are metadevices
    962 			 */
    963 			if (metaismeta(tp->masternamep)) {
    964 				/* get a mdnamelist_t. */
    965 				newlp = create_nlp(sp);
    966 				newlp->namep = tp->masternamep;
    967 				if (toplp == NULL) {
    968 					toplp = tailp = newlp;
    969 				} else {
    970 					tailp->next = newlp;
    971 					tailp = newlp;
    972 				}
    973 				ntoptrans++;
    974 			}
    975 
    976 			if (tp->lognamep && metaismeta(tp->lognamep)) {
    977 				newlp = create_nlp(sp);
    978 				newlp->namep = tp->lognamep;
    979 				if (toplp == NULL) {
    980 					toplp = tailp = newlp;
    981 				} else {
    982 					tailp->next = newlp;
    983 					tailp = newlp;
    984 				}
    985 				ntoptrans++;
    986 			}
    987 			p = p->next;
    988 		}
    989 	}
    990 	*top_pp = toplp;
    991 	return (ntoptrans);
    992 }
    993 
    994 void
    995 probe_mirror_devs(mdsetname_t *sp)
    996 {
    997 	mdnamelist_t	*nlp, *toplp;
    998 	int		cnt;
    999 	md_error_t	e = mdnullerror;
   1000 
   1001 	nlp = toplp = NULL;
   1002 
   1003 	if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) {
   1004 		/*
   1005 		 * We have some mirrors to probe
   1006 		 * get a list of top-level mirrors
   1007 		 */
   1008 
   1009 		cnt = get_toplevel_mds(sp, &nlp, &toplp);
   1010 		if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_MIRROR) < 0))
   1011 				perror("MD_IOCPROBE_DEV");
   1012 	} else {
   1013 		mdclrerror(&e);
   1014 	}
   1015 	metafreenamelist(nlp);
   1016 	metafreenamelist(toplp);
   1017 
   1018 }
   1019 
   1020 void
   1021 probe_raid_devs(mdsetname_t *sp)
   1022 {
   1023 	mdnamelist_t	*nlp, *toplp;
   1024 	int		cnt;
   1025 	md_error_t	e = mdnullerror;
   1026 
   1027 	nlp = toplp = NULL;
   1028 
   1029 	if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) {
   1030 		/*
   1031 		 * We have some mirrors to probe
   1032 		 * get a list of top-level mirrors
   1033 		 */
   1034 
   1035 		cnt = get_toplevel_mds(sp, &nlp, &toplp);
   1036 
   1037 		if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_RAID) < 0))
   1038 			perror("MD_IOCPROBE_DEV");
   1039 	} else {
   1040 		mdclrerror(&e);
   1041 	}
   1042 	metafreenamelist(nlp);
   1043 	metafreenamelist(toplp);
   1044 }
   1045 
   1046 /*
   1047  * Trans probes are diffenent. -- so whats new.
   1048  * we separate out the master and log device and then issue the
   1049  * probe calls.
   1050  * Since the underlying device could be disk, stripe, RAID or miror,
   1051  * we have to sort them out and then call the ioctl for each.
   1052  */
   1053 
   1054 void
   1055 probe_trans_devs(mdsetname_t *sp)
   1056 {
   1057 	mdnamelist_t	*nlp, *toplp;
   1058 	mdnamelist_t	*trans_raidlp, *trans_mmlp, *trans_stripelp;
   1059 	int		cnt;
   1060 	md_error_t	e = mdnullerror;
   1061 
   1062 	nlp = toplp = NULL;
   1063 	trans_raidlp = trans_mmlp = trans_stripelp = NULL;
   1064 
   1065 	if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) {
   1066 		/*
   1067 		 * get a list of master and log metadevices.
   1068 		 */
   1069 
   1070 		cnt = create_trans_compslist(sp, &nlp, &toplp);
   1071 
   1072 		/* underlying RAID-5 components */
   1073 
   1074 		cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID);
   1075 		if ((cnt > 0) && (md_probe_ioctl(sp, trans_raidlp, cnt,
   1076 		    MD_RAID) < 0))
   1077 			perror("MD_IOCPROBE_DEV");
   1078 
   1079 		metafreenamelist(trans_raidlp);
   1080 
   1081 		/* underlying mirror components */
   1082 
   1083 		cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR);
   1084 
   1085 		if ((cnt > 0) && (md_probe_ioctl(sp, trans_mmlp, cnt,
   1086 		    MD_MIRROR) < 0))
   1087 			perror("MD_IOCPROBE_DEV");
   1088 
   1089 		metafreenamelist(trans_mmlp);
   1090 
   1091 		/* underlying stripe components */
   1092 
   1093 		cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE);
   1094 		if ((cnt > 0) && (md_probe_ioctl(sp, trans_stripelp, cnt,
   1095 		    MD_STRIPE) < 0))
   1096 			perror("MD_IOCPROBE_DEV");
   1097 		metafreenamelist(trans_stripelp);
   1098 		metafreenamelist(nlp);
   1099 	} else {
   1100 		mdclrerror(&e);
   1101 	}
   1102 }
   1103 
   1104 /*
   1105  * probe hot spares. This is differs from other approaches since
   1106  * there are no read/write routines through md. We check at the physical
   1107  * component level and then delete it if its bad.
   1108  */
   1109 
   1110 void
   1111 probe_hotspare_devs(mdsetname_t *sp)
   1112 {
   1113 	mdhspnamelist_t *hspnlp = NULL;
   1114 	mdhspnamelist_t	*p;
   1115 	md_hsp_t	*hspp;
   1116 	md_error_t	e = mdnullerror;
   1117 
   1118 	if (meta_get_hsp_names(sp, &hspnlp, 0, &e) <= 0) {
   1119 		mdclrerror(&e);
   1120 		return;
   1121 	}
   1122 	for (p = hspnlp; (p != NULL); p = p->next) {
   1123 		mdhspname_t	*hspnp = p->hspnamep;
   1124 
   1125 		if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL)
   1126 			continue;
   1127 
   1128 		if (hspp->hotspares.hotspares_len != 0) {
   1129 			delete_hotspares_impl(sp, hspnp, hspp);
   1130 		}
   1131 	}
   1132 	metafreehspnamelist(hspnlp);
   1133 	mdclrerror(&e);
   1134 }
   1135 
   1136 static void
   1137 probe_all_devs(mdsetname_t *sp)
   1138 {
   1139 	probe_hotspare_devs(sp);
   1140 	probe_mirror_devs(sp);
   1141 	probe_raid_devs(sp);
   1142 	probe_trans_devs(sp);
   1143 }
   1144 
   1145 /*
   1146  * The following functions are used to print the concise output
   1147  * of the metastat coommand (-c option).
   1148  *
   1149  * Normally the output for metastat is performed within libmeta via
   1150  * the *_report functions within each of the metadevice specific files in
   1151  * libmeta.  However, it is usually bad architecture for a library to
   1152  * perform output since there are so many different ways that an application
   1153  * can choose to do output (e.g. GUI, CLI, CIM, SNMP, etc.).  So, for the
   1154  * concise output option we have moved the CLI output to the metastat
   1155  * code and just use libmeta as the source of data to be printed.
   1156  *
   1157  * This function gets all of the different top-level metadevices in the set
   1158  * and prints them.  It calls the print_concise_md() function to recursively
   1159  * print the metadevices that underly the top-level metadevices.  It does
   1160  * special handling for soft partitions so that all of the SPs on the
   1161  * same underlying device are grouped and then that underlying device
   1162  * is only printed once.
   1163  */
   1164 static void
   1165 print_concise_diskset(mdsetname_t *sp)
   1166 {
   1167 	md_error_t		error = mdnullerror;
   1168 	mdnamelist_t		*nl = NULL;
   1169 	mdhspnamelist_t		*hsp_list = NULL;
   1170 
   1171 	/*
   1172 	 * We do extra handling for soft parts since we want to find
   1173 	 * all of the SPs on the same underlying device, group them and
   1174 	 * print them together before printing the underlying device just
   1175 	 * once.  This logic doesn't apply to any other metadevice type.
   1176 	 */
   1177 	if (meta_get_sp_names(sp, &nl, 0, &error) >= 0) {
   1178 		mdnamelist_t	*nlp;
   1179 		/* keep track of the softparts on the same underlying device */
   1180 		struct sp_base_list	*base_list = NULL;
   1181 
   1182 		for (nlp = nl; nlp != NULL; nlp = nlp->next) {
   1183 			mdname_t	*mdn;
   1184 			md_sp_t		*soft_part;
   1185 			mdnamelist_t	*tnlp;
   1186 
   1187 			mdn = metaname(&sp, nlp->namep->cname,
   1188 			    META_DEVICE, &error);
   1189 			mdclrerror(&error);
   1190 			if (mdn == NULL) {
   1191 				print_concise_entry(0, nlp->namep->cname,
   1192 				    0, 'p');
   1193 				(void) printf("\n");
   1194 				continue;
   1195 			}
   1196 
   1197 			soft_part = meta_get_sp_common(sp, mdn, 1, &error);
   1198 			mdclrerror(&error);
   1199 
   1200 			if (soft_part == NULL ||
   1201 			    MD_HAS_PARENT(soft_part->common.parent) ||
   1202 			    sp_done(soft_part, base_list))
   1203 				continue;
   1204 
   1205 			/* print this soft part */
   1206 			print_concise_entry(0, soft_part->common.namep->cname,
   1207 			    soft_part->common.size, 'p');
   1208 			(void) printf(" %s\n", soft_part->compnamep->cname);
   1209 
   1210 			/*
   1211 			 * keep track of the underlying device of
   1212 			 * this soft part
   1213 			 */
   1214 			base_list = sp_add_done(soft_part, base_list);
   1215 
   1216 			/*
   1217 			 * now print all of the other soft parts on the same
   1218 			 * underlying device
   1219 			 */
   1220 			for (tnlp = nlp->next; tnlp != NULL; tnlp =
   1221 			    tnlp->next) {
   1222 				md_sp_t		*part;
   1223 
   1224 				mdn = metaname(&sp, tnlp->namep->cname,
   1225 				    META_DEVICE, &error);
   1226 
   1227 				mdclrerror(&error);
   1228 				if (mdn == NULL)
   1229 					continue;
   1230 
   1231 				part = meta_get_sp_common(sp, mdn, 1, &error);
   1232 				mdclrerror(&error);
   1233 
   1234 				if (part == NULL || MD_HAS_PARENT(
   1235 				    part->common.parent) ||
   1236 				    ! sp_match(part, base_list))
   1237 					continue;
   1238 
   1239 				/* on the same base so print this soft part */
   1240 				print_concise_entry(0,
   1241 				    part->common.namep->cname,
   1242 				    part->common.size, 'p');
   1243 				(void) printf(" %s\n", part->compnamep->cname);
   1244 			}
   1245 
   1246 			/*
   1247 			 * print the common metadevice hierarchy
   1248 			 * under these soft parts
   1249 			 */
   1250 			print_concise_md(META_INDENT, sp, soft_part->compnamep);
   1251 		}
   1252 
   1253 		free_names(&nl);
   1254 		sp_free_list(base_list);
   1255 	}
   1256 	mdclrerror(&error);
   1257 
   1258 	if (meta_get_trans_names(sp, &nl, 0, &error) >= 0)
   1259 		print_concise_namelist(sp, &nl, 't');
   1260 	mdclrerror(&error);
   1261 
   1262 	if (meta_get_mirror_names(sp, &nl, 0, &error) >= 0)
   1263 		print_concise_namelist(sp, &nl, 'm');
   1264 	mdclrerror(&error);
   1265 
   1266 	if (meta_get_raid_names(sp, &nl, 0, &error) >= 0)
   1267 		print_concise_namelist(sp, &nl, 'r');
   1268 	mdclrerror(&error);
   1269 
   1270 	if (meta_get_stripe_names(sp, &nl, 0, &error) >= 0)
   1271 		print_concise_namelist(sp, &nl, 's');
   1272 	mdclrerror(&error);
   1273 
   1274 	if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) {
   1275 		mdhspnamelist_t *nlp;
   1276 
   1277 	for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) {
   1278 		md_hsp_t	*hsp;
   1279 
   1280 		print_concise_entry(0, nlp->hspnamep->hspname, 0, 'h');
   1281 
   1282 		hsp = meta_get_hsp_common(sp, nlp->hspnamep, 1, &error);
   1283 		mdclrerror(&error);
   1284 		if (hsp != NULL) {
   1285 			int	i;
   1286 
   1287 			for (i = 0; i < hsp->hotspares.hotspares_len; i++) {
   1288 				md_hs_t	*hs;
   1289 				char	*state;
   1290 
   1291 				hs = &hsp->hotspares.hotspares_val[i];
   1292 
   1293 				(void) printf(" %s", hs->hsnamep->cname);
   1294 
   1295 				state = get_hs_state(hs);
   1296 				if (state != NULL)
   1297 					(void) printf(" (%s)", state);
   1298 			}
   1299 		}
   1300 
   1301 		(void) printf("\n");
   1302 	}
   1303 
   1304 	mdclrerror(&error);
   1305 	metafreehspnamelist(hsp_list);
   1306 	}
   1307 }
   1308 
   1309 /*
   1310  * Print the top-level metadevices in the name list for concise output.
   1311  */
   1312 static void
   1313 print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, char mtype)
   1314 {
   1315 	mdnamelist_t	*nlp;
   1316 	md_error_t	error = mdnullerror;
   1317 
   1318 	for (nlp = *nl; nlp != NULL; nlp = nlp->next) {
   1319 		mdname_t	*mdn;
   1320 		md_common_t	*u;
   1321 
   1322 		mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
   1323 		mdclrerror(&error);
   1324 		if (mdn == NULL) {
   1325 			print_concise_entry(0, nlp->namep->cname, 0, mtype);
   1326 			(void) printf("\n");
   1327 			continue;
   1328 		}
   1329 
   1330 		u = get_concise_unit(sp, mdn, &error);
   1331 		mdclrerror(&error);
   1332 
   1333 		if (u != NULL && !MD_HAS_PARENT(u->parent))
   1334 			print_concise_md(0, sp, mdn);
   1335 	}
   1336 
   1337 	free_names(nl);
   1338 }
   1339 
   1340 /*
   1341  * Concise mirror output.
   1342  */
   1343 static void
   1344 print_concise_mirror(int indent, mdsetname_t *sp, md_mirror_t *mirror)
   1345 {
   1346 	md_error_t	error = mdnullerror;
   1347 	int		i;
   1348 	md_status_t	status = mirror->common.state;
   1349 
   1350 	if (mirror == NULL)
   1351 		return;
   1352 
   1353 	print_concise_entry(indent, mirror->common.namep->cname,
   1354 	    mirror->common.size, 'm');
   1355 
   1356 	for (i = 0; i < NMIRROR; i++) {
   1357 		uint_t	tstate = 0;
   1358 		char	*state;
   1359 
   1360 		if (mirror->submirrors[i].submirnamep == NULL)
   1361 			continue;
   1362 		(void) printf(" %s", mirror->submirrors[i].submirnamep->cname);
   1363 
   1364 		if (mirror->submirrors[i].state & SMS_OFFLINE) {
   1365 			(void) printf(gettext(" (offline)"));
   1366 			continue;
   1367 		}
   1368 
   1369 		if (metaismeta(mirror->submirrors[i].submirnamep))
   1370 			(void) meta_get_tstate(
   1371 			    mirror->submirrors[i].submirnamep->dev,
   1372 			    &tstate, &error);
   1373 
   1374 		mdclrerror(&error);
   1375 		state = get_sm_state(mirror, i, status, tstate);
   1376 		if (state != NULL)
   1377 			(void) printf(" (%s)", state);
   1378 	}
   1379 
   1380 	(void) printf("\n");
   1381 
   1382 	indent += META_INDENT;
   1383 	for (i = 0; i < NMIRROR; i++) {
   1384 		if (mirror->submirrors[i].submirnamep == NULL)
   1385 			continue;
   1386 
   1387 		print_concise_md(indent, sp, mirror->submirrors[i].submirnamep);
   1388 	}
   1389 }
   1390 
   1391 /*
   1392  * Concise raid output.
   1393  */
   1394 static void
   1395 print_concise_raid(int indent, mdsetname_t *sp, md_raid_t *raid)
   1396 {
   1397 	md_error_t	error = mdnullerror;
   1398 	int		i;
   1399 	uint_t		tstate = 0;
   1400 
   1401 	if (raid == NULL)
   1402 		return;
   1403 
   1404 	print_concise_entry(indent, raid->common.namep->cname,
   1405 	    raid->common.size, 'r');
   1406 
   1407 	if (metaismeta(raid->common.namep))
   1408 		(void) meta_get_tstate(raid->common.namep->dev,
   1409 		    &tstate, &error);
   1410 
   1411 	for (i = 0; i < raid->cols.cols_len; i++) {
   1412 		md_raidcol_t	*colp = &raid->cols.cols_val[i];
   1413 		mdname_t	*namep = ((colp->hsnamep != NULL) ?
   1414 		    colp->hsnamep : colp->colnamep);
   1415 		char	*hsname = ((colp->hsnamep != NULL) ?
   1416 		    colp->hsnamep->cname : NULL);
   1417 		char	*col_state = NULL;
   1418 
   1419 		(void) printf(" %s", colp->colnamep->cname);
   1420 
   1421 		if (metaismeta(namep)) {
   1422 			uint_t tstate = 0;
   1423 
   1424 			(void) meta_get_tstate(namep->dev, &tstate, &error);
   1425 			mdclrerror(&error);
   1426 			col_state = get_raid_col_state(colp, tstate);
   1427 
   1428 		} else {
   1429 			if (tstate != 0)
   1430 				col_state = "-";
   1431 			else
   1432 				col_state = get_raid_col_state(colp, tstate);
   1433 		}
   1434 
   1435 		if (col_state != NULL) {
   1436 			if (hsname != NULL)
   1437 				(void) printf(" (%s-%s)", col_state, hsname);
   1438 			else
   1439 				(void) printf(" (%s)", col_state);
   1440 
   1441 		} else if (hsname != NULL) {
   1442 			(void) printf(gettext(" (spared-%s)"), hsname);
   1443 		}
   1444 	}
   1445 
   1446 	(void) printf("\n");
   1447 
   1448 	indent += META_INDENT;
   1449 	for (i = 0; i < raid->cols.cols_len; i++) {
   1450 		print_concise_md(indent, sp, raid->cols.cols_val[i].colnamep);
   1451 	}
   1452 }
   1453 
   1454 /*
   1455  * Concise stripe output.
   1456  */
   1457 static void
   1458 print_concise_stripe(int indent, mdsetname_t *sp, md_stripe_t *stripe)
   1459 {
   1460 	md_error_t	error = mdnullerror;
   1461 	int		i;
   1462 	uint_t		top_tstate = 0;
   1463 
   1464 	if (stripe == NULL)
   1465 		return;
   1466 
   1467 	print_concise_entry(indent, stripe->common.namep->cname,
   1468 	    stripe->common.size, 's');
   1469 
   1470 	if (metaismeta(stripe->common.namep))
   1471 		(void) meta_get_tstate(stripe->common.namep->dev, &top_tstate,
   1472 		    &error);
   1473 	mdclrerror(&error);
   1474 
   1475 	for (i = 0; i < stripe->rows.rows_len; i++) {
   1476 		md_row_t	*rowp;
   1477 		int		j;
   1478 
   1479 		rowp = &stripe->rows.rows_val[i];
   1480 
   1481 		for (j = 0; j < rowp->comps.comps_len; j++) {
   1482 			md_comp_t	*comp;
   1483 			uint_t		tstate = 0;
   1484 			char		*comp_state = NULL;
   1485 			char		*hsname;
   1486 
   1487 			comp = &rowp->comps.comps_val[j];
   1488 			(void) printf(" %s", comp->compnamep->cname);
   1489 
   1490 			if (metaismeta(comp->compnamep)) {
   1491 				uint_t tstate = 0;
   1492 				(void) meta_get_tstate(comp->compnamep->dev,
   1493 				    &tstate, &error);
   1494 				mdclrerror(&error);
   1495 				comp_state = get_stripe_state(comp, tstate);
   1496 			} else {
   1497 			if (top_tstate != 0)
   1498 				comp_state = "-";
   1499 			else
   1500 				comp_state = get_stripe_state(comp, tstate);
   1501 			}
   1502 
   1503 			hsname = ((comp->hsnamep != NULL) ?
   1504 			    comp->hsnamep->cname : NULL);
   1505 
   1506 			if (comp_state != NULL) {
   1507 				if (hsname != NULL)
   1508 					(void) printf(" (%s-%s)",
   1509 					    comp_state, hsname);
   1510 				else
   1511 					(void) printf(" (%s)", comp_state);
   1512 
   1513 			} else if (hsname != NULL) {
   1514 				(void) printf(gettext(" (spared-%s)"), hsname);
   1515 			}
   1516 		}
   1517 	}
   1518 
   1519 	(void) printf("\n");
   1520 
   1521 	indent += META_INDENT;
   1522 	for (i = 0; i < stripe->rows.rows_len; i++) {
   1523 		md_row_t	*rowp;
   1524 		int		j;
   1525 
   1526 		rowp = &stripe->rows.rows_val[i];
   1527 
   1528 		for (j = 0; j < rowp->comps.comps_len; j++) {
   1529 			print_concise_md(indent, sp,
   1530 			    rowp->comps.comps_val[j].compnamep);
   1531 		}
   1532 	}
   1533 }
   1534 
   1535 /*
   1536  * Concise soft partition output.
   1537  */
   1538 static void
   1539 print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part)
   1540 {
   1541 	if (part == NULL)
   1542 	return;
   1543 
   1544 	print_concise_entry(indent, part->common.namep->cname,
   1545 	    part->common.size, 'p');
   1546 
   1547 	(void) printf(" %s\n", part->compnamep->cname);
   1548 
   1549 	print_concise_md(indent + META_INDENT, sp, part->compnamep);
   1550 }
   1551 
   1552 /*
   1553  * Concise trans output.
   1554  */
   1555 static void
   1556 print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans)
   1557 {
   1558 	if (trans == NULL)
   1559 		return;
   1560 
   1561 	print_concise_entry(indent, trans->common.namep->cname,
   1562 	    trans->common.size, 't');
   1563 
   1564 	if (trans->masternamep != NULL)
   1565 		(void) printf(" %s", trans->masternamep->cname);
   1566 
   1567 	if (trans->lognamep != NULL)
   1568 		(void) printf(" %s", trans->lognamep->cname);
   1569 
   1570 	(void) printf("\n");
   1571 
   1572 	indent += META_INDENT;
   1573 
   1574 	print_concise_md(indent, sp, trans->masternamep);
   1575 
   1576 	print_concise_md(indent, sp, trans->lognamep);
   1577 }
   1578 
   1579 /*
   1580  * Recursive function for concise metadevice nested output.
   1581  */
   1582 static void
   1583 print_concise_md(int indent, mdsetname_t *sp, mdname_t *np)
   1584 {
   1585 	md_error_t	error = mdnullerror;
   1586 	md_unit_t	*u;
   1587 	md_mirror_t	*mirror;
   1588 	md_raid_t	*raid;
   1589 	md_sp_t		*soft_part;
   1590 	md_stripe_t	*stripe;
   1591 	md_trans_t	*trans;
   1592 
   1593 	if (np == NULL || !metaismeta(np))
   1594 		return;
   1595 
   1596 	if ((u = meta_get_mdunit(sp, np, &error)) == NULL) {
   1597 		mdclrerror(&error);
   1598 		return;
   1599 	}
   1600 
   1601 	switch (u->c.un_type) {
   1602 		case MD_DEVICE:
   1603 			stripe = meta_get_stripe_common(sp, np, 1, &error);
   1604 			print_concise_stripe(indent, sp, stripe);
   1605 			break;
   1606 
   1607 		case MD_METAMIRROR:
   1608 			mirror = meta_get_mirror(sp, np, &error);
   1609 			print_concise_mirror(indent, sp, mirror);
   1610 			break;
   1611 
   1612 		case MD_METATRANS:
   1613 			trans = meta_get_trans_common(sp, np, 1, &error);
   1614 			print_concise_trans(indent, sp, trans);
   1615 			break;
   1616 
   1617 		case MD_METARAID:
   1618 			raid = meta_get_raid_common(sp, np, 1, &error);
   1619 			print_concise_raid(indent, sp, raid);
   1620 			break;
   1621 
   1622 		case MD_METASP:
   1623 			soft_part = meta_get_sp_common(sp, np, 1, &error);
   1624 			print_concise_sp(indent, sp, soft_part);
   1625 			break;
   1626 
   1627 		default:
   1628 			return;
   1629 	}
   1630 	mdclrerror(&error);
   1631 }
   1632 
   1633 /*
   1634  * Given a name get the unit for use in concise output.  We use the *_common
   1635  * routines in libmeta which allow us to specify the "fast" flag, thereby
   1636  * avoiding the DKIOCGGEOM ioctl that normally happens.
   1637  */
   1638 static md_common_t *
   1639 get_concise_unit(mdsetname_t *sp, mdname_t *np, md_error_t *ep)
   1640 {
   1641 	char		*miscname;
   1642 
   1643 	/* short circuit */
   1644 	if (np->drivenamep->unitp != NULL)
   1645 		return (np->drivenamep->unitp);
   1646 	if (metachkmeta(np, ep) != 0)
   1647 		return (NULL);
   1648 
   1649 	/* dispatch */
   1650 	if ((miscname = metagetmiscname(np, ep)) == NULL)
   1651 		return (NULL);
   1652 	else if (strcmp(miscname, MD_STRIPE) == 0)
   1653 		return ((md_common_t *)meta_get_stripe_common(sp, np, 1, ep));
   1654 	else if (strcmp(miscname, MD_MIRROR) == 0)
   1655 		return ((md_common_t *)meta_get_mirror(sp, np, ep));
   1656 	else if (strcmp(miscname, MD_TRANS) == 0)
   1657 		return ((md_common_t *)meta_get_trans_common(sp, np, 1, ep));
   1658 	else if (strcmp(miscname, MD_RAID) == 0)
   1659 		return ((md_common_t *)meta_get_raid_common(sp, np, 1, ep));
   1660 	else if (strcmp(miscname, MD_SP) == 0)
   1661 		return ((md_common_t *)meta_get_sp_common(sp, np, 1, ep));
   1662 	else {
   1663 		(void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev),
   1664 		    np->cname);
   1665 		return (NULL);
   1666 	}
   1667 }
   1668 
   1669 static void
   1670 free_names(mdnamelist_t **nlp)
   1671 {
   1672 	mdnamelist_t *p;
   1673 
   1674 	for (p = *nlp; p != NULL; p = p->next) {
   1675 		meta_invalidate_name(p->namep);
   1676 		p->namep = NULL;
   1677 	}
   1678 	metafreenamelist(*nlp);
   1679 	*nlp = NULL;
   1680 }
   1681 
   1682 /*
   1683  * Submirror state for concise output.
   1684  */
   1685 static char *
   1686 get_sm_state(md_mirror_t *mirror, int i, md_status_t mirror_status,
   1687 	uint_t tstate)
   1688 {
   1689 	sm_state_t	state = mirror->submirrors[i].state;
   1690 	uint_t	is_target =
   1691 	    mirror->submirrors[i].flags & MD_SM_RESYNC_TARGET;
   1692 
   1693 	/*
   1694 	 * Only return Unavailable if there is no flagged error on the
   1695 	 * submirror. If the mirror has received any writes since the submirror
   1696 	 * went into Unavailable state a resync is required. To alert the
   1697 	 * administrator to this we return a 'Needs maintenance' message.
   1698 	 */
   1699 	if ((tstate != 0) && (state & SMS_RUNNING))
   1700 		return (gettext("unavail"));
   1701 
   1702 	/* all is well */
   1703 	if (state & SMS_RUNNING) {
   1704 		if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
   1705 		    ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target))
   1706 			return (NULL);
   1707 	}
   1708 
   1709 	/* resyncing, needs repair */
   1710 	if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
   1711 	    SMS_OFFLINE_RESYNC)) || (mirror_status & MD_UN_OPT_NOT_DONE)) {
   1712 		static char buf[MAXPATHLEN];
   1713 
   1714 		if (mirror_status & MD_UN_RESYNC_ACTIVE) {
   1715 
   1716 			if (mirror->common.revision & MD_64BIT_META_DEV) {
   1717 				(void) snprintf(buf, sizeof (buf),
   1718 				    gettext("resync-%2d.%1d%%"),
   1719 				    mirror->percent_done / 10,
   1720 				    mirror->percent_done % 10);
   1721 			} else {
   1722 				(void) snprintf(buf, sizeof (buf),
   1723 				gettext("resync-%d%%"), mirror->percent_done);
   1724 			}
   1725 			return (buf);
   1726 		}
   1727 		return (gettext("maint"));
   1728 	}
   1729 
   1730 	/* needs repair */
   1731 	if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE))
   1732 		return (gettext("maint"));
   1733 
   1734 	/* unknown */
   1735 	return (gettext("unknown"));
   1736 }
   1737 
   1738 /*
   1739  * Raid component state for concise output.
   1740  */
   1741 static char *
   1742 get_raid_col_state(md_raidcol_t *colp, uint_t tstate)
   1743 {
   1744 	if (tstate != 0)
   1745 		return (gettext("unavail"));
   1746 
   1747 	return (meta_get_raid_col_state(colp->state));
   1748 }
   1749 
   1750 /*
   1751  * Stripe state for concise output.
   1752  */
   1753 static char *
   1754 get_stripe_state(md_comp_t *mdcp, uint_t tstate)
   1755 {
   1756 	comp_state_t	state = mdcp->state;
   1757 
   1758 	if (tstate != 0)
   1759 		return ("unavail");
   1760 
   1761 	return (meta_get_stripe_state(state));
   1762 }
   1763 
   1764 /*
   1765  * Hostspare state for concise output.
   1766  */
   1767 static char *
   1768 get_hs_state(md_hs_t *hsp)
   1769 {
   1770 	hotspare_states_t	state = hsp->state;
   1771 
   1772 	return (meta_get_hs_state(state));
   1773 }
   1774 
   1775 
   1776 /*
   1777  * Keep track of printed soft partitions for concise output.
   1778  */
   1779 static struct sp_base_list *
   1780 sp_add_done(md_sp_t *part, struct sp_base_list *lp)
   1781 {
   1782 	struct sp_base_list *n;
   1783 
   1784 	n = (struct sp_base_list *)malloc(sizeof (struct sp_base_list));
   1785 	if (n == NULL)
   1786 		return (lp);
   1787 
   1788 	if ((n->base = strdup(part->compnamep->cname)) == NULL) {
   1789 		free(n);
   1790 		return (lp);
   1791 	}
   1792 
   1793 	n->next = lp;
   1794 
   1795 	return (n);
   1796 }
   1797 
   1798 /*
   1799  * Keep track of printed soft partitions for concise output.
   1800  */
   1801 static int
   1802 sp_done(md_sp_t *part, struct sp_base_list *lp)
   1803 {
   1804 	for (; lp != NULL; lp = lp->next) {
   1805 		if (strcmp(lp->base, part->compnamep->cname) == 0)
   1806 			return (1);
   1807 	}
   1808 
   1809 	return (0);
   1810 }
   1811 
   1812 /*
   1813  * Check the first element for a match.
   1814  */
   1815 static int
   1816 sp_match(md_sp_t *part, struct sp_base_list *lp)
   1817 {
   1818 	if (lp != NULL && strcmp(lp->base, part->compnamep->cname) == 0)
   1819 		return (1);
   1820 
   1821 	return (0);
   1822 }
   1823 
   1824 /*
   1825  * Free memory used for soft partition printed status in concise output.
   1826  */
   1827 static void
   1828 sp_free_list(struct sp_base_list *lp)
   1829 {
   1830 	struct sp_base_list *n;
   1831 
   1832 	for (; lp != NULL; lp = n) {
   1833 		n = lp->next;
   1834 		free(lp->base);
   1835 		free(lp);
   1836 	}
   1837 }
   1838