xref: /onnv-gate/usr/src/cmd/lvm/util/metaset.c (revision 1945:74cee1cd404b)
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
51320Srd117015  * Common Development and Distribution License (the "License").
61320Srd117015  * 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 /*
221320Srd117015  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Metadevice diskset utility.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <meta.h>
330Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
340Sstevel@tonic-gate #include <sdssc.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate enum metaset_cmd {
370Sstevel@tonic-gate 	notspecified,
380Sstevel@tonic-gate 	add,
390Sstevel@tonic-gate 	balance,
400Sstevel@tonic-gate 	delete,
410Sstevel@tonic-gate 	cluster,
420Sstevel@tonic-gate 	isowner,
430Sstevel@tonic-gate 	purge,
440Sstevel@tonic-gate 	query,
450Sstevel@tonic-gate 	release,
460Sstevel@tonic-gate 	take,
470Sstevel@tonic-gate 	join,			/* Join a multinode diskset */
480Sstevel@tonic-gate 	withdraw		/* Withdraw from a multinode diskset */
490Sstevel@tonic-gate };
500Sstevel@tonic-gate 
510Sstevel@tonic-gate enum cluster_cmd {
520Sstevel@tonic-gate 	ccnotspecified,
530Sstevel@tonic-gate 	clusterversion,		/* Return the version of the cluster I/F */
540Sstevel@tonic-gate 	clusterdisksin,		/* List disks in a given diskset */
550Sstevel@tonic-gate 	clustertake,		/* back door for Cluster take */
560Sstevel@tonic-gate 	clusterrelease,		/* ditto */
570Sstevel@tonic-gate 	clusterpurge,		/* back door for Cluster purge */
580Sstevel@tonic-gate 	clusterproxy		/* proxy the args after '--' to primary */
590Sstevel@tonic-gate };
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static void
620Sstevel@tonic-gate usage(
630Sstevel@tonic-gate 	mdsetname_t	*sp,
640Sstevel@tonic-gate 	char		*string)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	if ((string != NULL) && (*string != '\0'))
670Sstevel@tonic-gate 		md_eprintf("%s\n", string);
680Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
690Sstevel@tonic-gate "usage:	%s -s setname -a [-A enable | disable] -h hostname ...\n"
700Sstevel@tonic-gate "	%s -s setname -a [-M] -h hostname ...\n"
710Sstevel@tonic-gate "	%s -s setname -a [-M] [-l length] [-L] drivename ...\n"
720Sstevel@tonic-gate "	%s -s setname -d [-M] -h hostname ...\n"
730Sstevel@tonic-gate "	%s -s setname -d [-M] -f -h all-hostnames\n"
740Sstevel@tonic-gate "	%s -s setname -d [-M] [-f] drivename ...\n"
750Sstevel@tonic-gate "	%s -s setname -d [-M] [-f] hostname ...\n"
760Sstevel@tonic-gate "	%s -s setname -A enable | disable\n"
770Sstevel@tonic-gate "	%s -s setname -t [-f]\n"
780Sstevel@tonic-gate "	%s -s setname -r\n"
790Sstevel@tonic-gate "	%s [-s setname] -j [-M]\n"
800Sstevel@tonic-gate "	%s [-s setname] -w [-M]\n"
810Sstevel@tonic-gate "	%s -s setname -P [-M]\n"
820Sstevel@tonic-gate "	%s -s setname -b [-M]\n"
830Sstevel@tonic-gate "	%s -s setname -o [-M] [-h hostname]\n"
840Sstevel@tonic-gate "	%s [-s setname]\n"
850Sstevel@tonic-gate "\n"
860Sstevel@tonic-gate "		hostname = contents of /etc/nodename\n"
870Sstevel@tonic-gate "		drivename = cNtNdN no slice\n"
880Sstevel@tonic-gate "		[-M] for multi-owner set is optional except on set creation\n"),
890Sstevel@tonic-gate 	myname, myname, myname, myname, myname, myname, myname, myname,
900Sstevel@tonic-gate 	myname, myname, myname, myname, myname, myname, myname, myname);
910Sstevel@tonic-gate 	md_exit(sp, (string == NULL) ? 0 : 1);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * The svm.sync rc script relies heavily on the metaset output.
960Sstevel@tonic-gate  * Any changes to the metaset output MUST verify that the rc script
970Sstevel@tonic-gate  * does not break. Not doing so may potentially leave the system
980Sstevel@tonic-gate  * unusable. You have been WARNED.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate static int
1010Sstevel@tonic-gate printset(mdsetname_t *sp, md_error_t *ep)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 	int			i, j;
1040Sstevel@tonic-gate 	md_set_desc		*sd;
1050Sstevel@tonic-gate 	md_drive_desc		*dd, *p;
1060Sstevel@tonic-gate 	int			max_meds;
1070Sstevel@tonic-gate 	md_mnnode_desc		*nd;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL)
1100Sstevel@tonic-gate 		return (-1);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/*
1130Sstevel@tonic-gate 	 * Only get set owner information for traditional diskset.
1140Sstevel@tonic-gate 	 * This set owner information is stored in the node records
1150Sstevel@tonic-gate 	 * for a MN diskset.
1160Sstevel@tonic-gate 	 */
1170Sstevel@tonic-gate 	if (!(MD_MNSET_DESC(sd))) {
1180Sstevel@tonic-gate 		if (metaget_setownership(sp, ep) == -1)
1190Sstevel@tonic-gate 			return (-1);
1200Sstevel@tonic-gate 	}
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
1230Sstevel@tonic-gate 	    ep)) == NULL) && !mdisok(ep))
1240Sstevel@tonic-gate 		return (-1);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
1270Sstevel@tonic-gate 		(void) printf(gettext(
1280Sstevel@tonic-gate 		"\nMulti-owner Set name = %s, Set number = %d, Master = %s\n"),
1290Sstevel@tonic-gate 		    sp->setname, sp->setno, sd->sd_mn_master_nodenm);
1300Sstevel@tonic-gate 		if ((sd->sd_mn_master_nodeid == MD_MN_INVALID_NID) &&
1310Sstevel@tonic-gate 		    (dd != NULL)) {
1320Sstevel@tonic-gate 			(void) printf(gettext(
1330Sstevel@tonic-gate 				"Master and owner information unavailable "
1340Sstevel@tonic-gate 				"until joined (metaset -j)\n"));
1350Sstevel@tonic-gate 		}
1360Sstevel@tonic-gate 	} else {
1370Sstevel@tonic-gate 		(void) printf(gettext(
1380Sstevel@tonic-gate 		    "\nSet name = %s, Set number = %d\n"),
1390Sstevel@tonic-gate 		    sp->setname, sp->setno);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
1430Sstevel@tonic-gate 		(void) printf(gettext("\n%-19.19s %-14.14s %-6.6s\n"),
1440Sstevel@tonic-gate 			gettext("Host"), gettext("Owner"), gettext("Member"));
1450Sstevel@tonic-gate 		nd = sd->sd_nodelist;
1460Sstevel@tonic-gate 		while (nd) {
1470Sstevel@tonic-gate 			/*
1480Sstevel@tonic-gate 			 * Don't print nodes that aren't ok since they may be
1490Sstevel@tonic-gate 			 * removed from config during a reconfig cycle.  If a
1500Sstevel@tonic-gate 			 * node was being added to a diskset and the entire
1510Sstevel@tonic-gate 			 * cluster went down but the node being added was unable
1520Sstevel@tonic-gate 			 * to reboot, there's no way to know if that node had
1530Sstevel@tonic-gate 			 * its own node record set to OK or not.  So, node
1540Sstevel@tonic-gate 			 * record is left in ADD state during reconfig cycle.
1550Sstevel@tonic-gate 			 * When that node reboots and returns to the cluster,
1560Sstevel@tonic-gate 			 * the reconfig cycle will either remove the node
1570Sstevel@tonic-gate 			 * record (if not marked OK on that node) or will mark
1580Sstevel@tonic-gate 			 * it OK on all nodes.
1590Sstevel@tonic-gate 			 * It is very important to only remove a node record
1600Sstevel@tonic-gate 			 * from the other nodes when that node record is not
1610Sstevel@tonic-gate 			 * marked OK on its own node - otherwise, different
1620Sstevel@tonic-gate 			 * nodes would have different nodelists possibly
1630Sstevel@tonic-gate 			 * causing different nodes to to choose different
1640Sstevel@tonic-gate 			 * masters.
1650Sstevel@tonic-gate 			 */
1660Sstevel@tonic-gate 			if (!(nd->nd_flags & MD_MN_NODE_OK)) {
1670Sstevel@tonic-gate 				nd = nd->nd_next;
1680Sstevel@tonic-gate 				continue;
1690Sstevel@tonic-gate 			}
1700Sstevel@tonic-gate 			if ((nd->nd_flags & MD_MN_NODE_ALIVE) &&
1710Sstevel@tonic-gate 			    (nd->nd_flags & MD_MN_NODE_OWN)) {
1720Sstevel@tonic-gate 				(void) printf(
1730Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
1740Sstevel@tonic-gate 				    nd->nd_nodename, gettext("multi-owner"),
1750Sstevel@tonic-gate 				    gettext("Yes"));
1760Sstevel@tonic-gate 			} else /* Should never be able to happen */
1770Sstevel@tonic-gate 			    if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) &&
1780Sstevel@tonic-gate 			    (nd->nd_flags & MD_MN_NODE_OWN)) {
1790Sstevel@tonic-gate 				(void) printf(
1800Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
1810Sstevel@tonic-gate 				    nd->nd_nodename, gettext("multi-owner"),
1820Sstevel@tonic-gate 				    gettext("No"));
1830Sstevel@tonic-gate 			} else if ((nd->nd_flags & MD_MN_NODE_ALIVE) &&
1840Sstevel@tonic-gate 			    (!(nd->nd_flags & MD_MN_NODE_OWN))) {
1850Sstevel@tonic-gate 				(void) printf(
1860Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
1870Sstevel@tonic-gate 				    nd->nd_nodename, gettext(""),
1880Sstevel@tonic-gate 				    gettext("Yes"));
1890Sstevel@tonic-gate 			} else if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) &&
1900Sstevel@tonic-gate 			    (!(nd->nd_flags & MD_MN_NODE_OWN))) {
1910Sstevel@tonic-gate 				(void) printf(
1920Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
1930Sstevel@tonic-gate 				    nd->nd_nodename, gettext(""),
1940Sstevel@tonic-gate 				    gettext("No"));
1950Sstevel@tonic-gate 			}
1960Sstevel@tonic-gate 			nd = nd->nd_next;
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 	} else {
1990Sstevel@tonic-gate 		(void) printf("\n%-19.19s %-5.5s\n",
2000Sstevel@tonic-gate 			gettext("Host"), gettext("Owner"));
2010Sstevel@tonic-gate 		for (i = 0; i < MD_MAXSIDES; i++) {
2020Sstevel@tonic-gate 			/* Skip empty slots */
2030Sstevel@tonic-gate 			if (sd->sd_nodes[i][0] == '\0')
2040Sstevel@tonic-gate 				continue;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 			/*
2070Sstevel@tonic-gate 			 * Standard hostname field is 17 bytes but metaset will
2080Sstevel@tonic-gate 			 * display up to MD_MAX_NODENAME, def in meta_basic.h
2090Sstevel@tonic-gate 			 */
2100Sstevel@tonic-gate 			(void) printf("  %-17.*s  %s\n", MD_MAX_NODENAME,
2110Sstevel@tonic-gate 			    sd->sd_nodes[i], (sd->sd_flags & MD_SR_AUTO_TAKE ?
2120Sstevel@tonic-gate 				(sd->sd_isown[i] ? gettext("Yes (auto)") :
2130Sstevel@tonic-gate 				    gettext("No (auto)"))
2140Sstevel@tonic-gate 				: (sd->sd_isown[i] ? gettext("Yes") : "")));
2150Sstevel@tonic-gate 		}
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if (sd->sd_med.n_cnt > 0)
2190Sstevel@tonic-gate 		(void) printf("\n%-19.19s %-7.7s\n",
2200Sstevel@tonic-gate 		    gettext("Mediator Host(s)"), gettext("Aliases"));
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	if ((max_meds = get_max_meds(ep)) == 0)
2230Sstevel@tonic-gate 		return (-1);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	for (i = 0; i < max_meds; i++) {
2260Sstevel@tonic-gate 		if (sd->sd_med.n_lst[i].a_cnt == 0)
2270Sstevel@tonic-gate 			continue;
2280Sstevel@tonic-gate 		(void) printf("  %-17.17s   ", sd->sd_med.n_lst[i].a_nm[0]);
2290Sstevel@tonic-gate 		for (j = 1; j < sd->sd_med.n_lst[i].a_cnt; j++) {
2300Sstevel@tonic-gate 			(void) printf("%s", sd->sd_med.n_lst[i].a_nm[j]);
2310Sstevel@tonic-gate 			if (sd->sd_med.n_lst[i].a_cnt - j > 1)
2320Sstevel@tonic-gate 				(void) printf(gettext(", "));
2330Sstevel@tonic-gate 		}
2340Sstevel@tonic-gate 		(void) printf("\n");
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (dd) {
2380Sstevel@tonic-gate 		int	len = 0;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 		/*
2420Sstevel@tonic-gate 		 * Building a format string on the fly that will
2430Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
2440Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
2450Sstevel@tonic-gate 		 * looking horrible.
2460Sstevel@tonic-gate 		 */
2470Sstevel@tonic-gate 		for (p = dd; p != NULL; p = p->dd_next)
2480Sstevel@tonic-gate 			len = max(len, strlen(p->dd_dnp->cname));
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		len += 2;
2510Sstevel@tonic-gate 		(void) printf("\n%-*.*s %-5.5s\n", len, len,
2520Sstevel@tonic-gate 		    gettext("Drive"),
2530Sstevel@tonic-gate 		    gettext("Dbase"));
2540Sstevel@tonic-gate 		for (p = dd; p != NULL; p = p->dd_next) {
2550Sstevel@tonic-gate 			(void) printf("\n%-*.*s %-5.5s\n", len, len,
2560Sstevel@tonic-gate 			    p->dd_dnp->cname,
2570Sstevel@tonic-gate 			    (p->dd_dbcnt ? gettext("Yes") :
2580Sstevel@tonic-gate 			    gettext("No")));
2590Sstevel@tonic-gate 		}
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	return (0);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate static int
2660Sstevel@tonic-gate printsets(mdsetname_t *sp, md_error_t *ep)
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	int			i;
2690Sstevel@tonic-gate 	mdsetname_t		*sp1;
2700Sstevel@tonic-gate 	set_t			max_sets;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/*
2730Sstevel@tonic-gate 	 * print setname given.
2740Sstevel@tonic-gate 	 */
2750Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
2760Sstevel@tonic-gate 		if (printset(sp, ep))
2770Sstevel@tonic-gate 			return (-1);
2780Sstevel@tonic-gate 		return (0);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if ((max_sets = get_max_sets(ep)) == 0)
2820Sstevel@tonic-gate 		return (-1);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	/*
2850Sstevel@tonic-gate 	 * Print all known sets
2860Sstevel@tonic-gate 	 */
2870Sstevel@tonic-gate 	for (i = 1; i < max_sets; i++) {
2880Sstevel@tonic-gate 		if ((sp1 = metasetnosetname(i, ep)) == NULL) {
2890Sstevel@tonic-gate 			if (! mdiserror(ep, MDE_NO_SET))
2900Sstevel@tonic-gate 				break;
2910Sstevel@tonic-gate 			mdclrerror(ep);
2920Sstevel@tonic-gate 			continue;
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		if (printset(sp1, ep))
2960Sstevel@tonic-gate 			break;
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 	if (! mdisok(ep))
2990Sstevel@tonic-gate 		return (-1);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	return (0);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate  * Print the current versionn of the cluster contract private interface.
3060Sstevel@tonic-gate  */
3070Sstevel@tonic-gate static void
3080Sstevel@tonic-gate printclusterversion()
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate 	printf("%s\n", METASETIFVERSION);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate  * Print the disks that make up the given disk set. This is used
3150Sstevel@tonic-gate  * exclusively by Sun Cluster and is contract private.
3160Sstevel@tonic-gate  * Should never be called with sname of a Multinode diskset.
3170Sstevel@tonic-gate  */
3180Sstevel@tonic-gate static int
3190Sstevel@tonic-gate printdisksin(char *sname, md_error_t *ep)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	mdsetname_t	*sp;
3220Sstevel@tonic-gate 	md_drive_desc	*dd, *p;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		/*
3270Sstevel@tonic-gate 		 * During a deletion of a set the associated service is
3280Sstevel@tonic-gate 		 * put offline. The SC3.0 reservation code calls disksuite
3290Sstevel@tonic-gate 		 * to find a list of disks associated with the set so that
3300Sstevel@tonic-gate 		 * it can release the reservation on those disks. In this
3310Sstevel@tonic-gate 		 * case there won't be any disks or even a set left. So just
3320Sstevel@tonic-gate 		 * return.
3330Sstevel@tonic-gate 		 */
3340Sstevel@tonic-gate 		return (0);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	if (metaget_setownership(sp, ep) == -1)
3380Sstevel@tonic-gate 		return (-1);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
3410Sstevel@tonic-gate 	    ep)) == NULL) && !mdisok(ep))
3420Sstevel@tonic-gate 		return (-1);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	for (p = dd; p != NULL; p = p->dd_next)
3450Sstevel@tonic-gate 		(void) printf("%s\n", p->dd_dnp->rname);
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	return (0);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate static void
3510Sstevel@tonic-gate parse_printset(int argc, char **argv)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	int		c;
3540Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
3550Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
3560Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
3570Sstevel@tonic-gate 	md_error_t	*ep = &status;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/* reset and parse args */
3600Sstevel@tonic-gate 	optind = 1;
3610Sstevel@tonic-gate 	opterr = 1;
3620Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "s:")) != -1) {
3630Sstevel@tonic-gate 		switch (c) {
3640Sstevel@tonic-gate 		case 's':
3650Sstevel@tonic-gate 			sname = optarg;
3660Sstevel@tonic-gate 			break;
3670Sstevel@tonic-gate 		default:
3680Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	argc -= optind;
3730Sstevel@tonic-gate 	argv += optind;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	if (argc != 0)
3760Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
3790Sstevel@tonic-gate 		mde_perror(ep, "");
3800Sstevel@tonic-gate 		md_exit(sp, 1);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	if (printsets(sp, ep) && !mdiserror(ep, MDE_SMF_NO_SERVICE)) {
3840Sstevel@tonic-gate 		mde_perror(ep, "");
3850Sstevel@tonic-gate 		md_exit(sp, 1);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
3890Sstevel@tonic-gate 		mde_perror(ep, "");
3900Sstevel@tonic-gate 		md_exit(sp, 1);
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	md_exit(sp, 0);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate static void
3970Sstevel@tonic-gate parse_add(int argc, char **argv)
3980Sstevel@tonic-gate {
3990Sstevel@tonic-gate 	int			c,
4000Sstevel@tonic-gate 				created_set,
4010Sstevel@tonic-gate 				hosts = FALSE,
4020Sstevel@tonic-gate 				meds = FALSE,
4030Sstevel@tonic-gate 				auto_take = FALSE,
4040Sstevel@tonic-gate 				force_label = FALSE,
4050Sstevel@tonic-gate 				default_size = TRUE;
4060Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
4070Sstevel@tonic-gate 	char			*sname = MD_LOCAL_NAME;
4080Sstevel@tonic-gate 	md_error_t		status = mdnullerror,
4090Sstevel@tonic-gate 				*ep = &status;
4100Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
4110Sstevel@tonic-gate 	mddrivenamelist_t	*p;
4120Sstevel@tonic-gate 	daddr_t			dbsize,
4130Sstevel@tonic-gate 				nblks;
4140Sstevel@tonic-gate 	mdsetname_t		*local_sp = NULL;
4150Sstevel@tonic-gate 	int			multi_node = 0;
4160Sstevel@tonic-gate 	md_set_desc		*sd;
4170Sstevel@tonic-gate 	rval_e			sdssc_rval;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	/* reset and parse args */
4200Sstevel@tonic-gate 	optind = 1;
4210Sstevel@tonic-gate 	opterr = 1;
4220Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "MaA:hl:Lms:")) != -1) {
4230Sstevel@tonic-gate 		switch (c) {
4240Sstevel@tonic-gate 		case 'M':
4250Sstevel@tonic-gate 			multi_node = 1;
4260Sstevel@tonic-gate 			break;
4270Sstevel@tonic-gate 		case 'A':
4280Sstevel@tonic-gate 			/* verified sub-option in main */
4290Sstevel@tonic-gate 			if (strcmp(optarg, "enable") == 0)
4300Sstevel@tonic-gate 				auto_take = TRUE;
4310Sstevel@tonic-gate 			break;
4320Sstevel@tonic-gate 		case 'a':
4330Sstevel@tonic-gate 			break;
4340Sstevel@tonic-gate 		case 'h':
4350Sstevel@tonic-gate 		case 'm':
4360Sstevel@tonic-gate 			if (meds == TRUE || hosts == TRUE)
4370Sstevel@tonic-gate 				usage(sp, gettext(
4380Sstevel@tonic-gate 				    "only one -m or -h option allowed"));
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 			if (default_size == FALSE || force_label == TRUE)
4410Sstevel@tonic-gate 				usage(sp, gettext(
4420Sstevel@tonic-gate 				    "conflicting options"));
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 			if (c == 'h')
4450Sstevel@tonic-gate 				hosts = TRUE;
4460Sstevel@tonic-gate 			else
4470Sstevel@tonic-gate 				meds = TRUE;
4480Sstevel@tonic-gate 			break;
4490Sstevel@tonic-gate 		case 'l':
4500Sstevel@tonic-gate 			if (hosts == TRUE || meds == TRUE)
4510Sstevel@tonic-gate 				usage(sp, gettext(
4520Sstevel@tonic-gate 				    "conflicting options"));
4530Sstevel@tonic-gate 			if (sscanf(optarg, "%ld", &dbsize) != 1) {
4540Sstevel@tonic-gate 				md_eprintf(gettext(
4550Sstevel@tonic-gate 				    "%s: bad format\n"), optarg);
4560Sstevel@tonic-gate 				usage(sp, "");
4570Sstevel@tonic-gate 			}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 			default_size = FALSE;
4600Sstevel@tonic-gate 			break;
4610Sstevel@tonic-gate 		case 'L':
4620Sstevel@tonic-gate 			/* Same criteria as -l */
4630Sstevel@tonic-gate 			if (hosts == TRUE || meds == TRUE)
4640Sstevel@tonic-gate 				usage(sp, gettext(
4650Sstevel@tonic-gate 				    "conflicting options"));
4660Sstevel@tonic-gate 			force_label = TRUE;
4670Sstevel@tonic-gate 			break;
4680Sstevel@tonic-gate 		case 's':
4690Sstevel@tonic-gate 			sname = optarg;
4700Sstevel@tonic-gate 			break;
4710Sstevel@tonic-gate 		default:
4720Sstevel@tonic-gate 			usage(sp, gettext(
4730Sstevel@tonic-gate 			    "unknown options"));
4740Sstevel@tonic-gate 		}
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	/* Can only use -A enable when creating the single-node set */
4780Sstevel@tonic-gate 	if (auto_take && hosts != TRUE)
4790Sstevel@tonic-gate 		usage(sp, gettext("conflicting options"));
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	argc -= optind;
4820Sstevel@tonic-gate 	argv += optind;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Add hosts
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	if (hosts == TRUE) {
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
4900Sstevel@tonic-gate 			mde_perror(ep, "");
4910Sstevel@tonic-gate 			md_exit(local_sp, 1);
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		if (meta_lock(local_sp, TRUE, ep) != 0) {
4950Sstevel@tonic-gate 			mde_perror(ep, "");
4960Sstevel@tonic-gate 			md_exit(local_sp, 1);
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		/*
5000Sstevel@tonic-gate 		 * Keep track of Cluster set creation. Need to complete
5010Sstevel@tonic-gate 		 * the transaction no matter if the set was created or not.
5020Sstevel@tonic-gate 		 */
5030Sstevel@tonic-gate 		created_set = 0;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		/*
5060Sstevel@tonic-gate 		 * Have no set, cannot take the lock, so only take the
5070Sstevel@tonic-gate 		 * local lock.
5080Sstevel@tonic-gate 		 */
5090Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) == NULL) {
5100Sstevel@tonic-gate 			sdssc_rval = 0;
5110Sstevel@tonic-gate 			if (multi_node) {
5120Sstevel@tonic-gate 				/*
5130Sstevel@tonic-gate 				 * When running on a cluster system that
5140Sstevel@tonic-gate 				 * does not support MN disksets, the routine
5150Sstevel@tonic-gate 				 * sdssc_mo_create_begin will be bound
5160Sstevel@tonic-gate 				 * to the SVM routine not_bound_error
5170Sstevel@tonic-gate 				 * which returns SDSSC_NOT_BOUND_ERROR.
5180Sstevel@tonic-gate 				 *
5190Sstevel@tonic-gate 				 * When running on a cluster system that
5200Sstevel@tonic-gate 				 * does support MN disksets, the routine
5210Sstevel@tonic-gate 				 * sdssc_mo_create_begin will be bound to
5220Sstevel@tonic-gate 				 * the sdssc_mo_create_begin routine in
5230Sstevel@tonic-gate 				 * library libsdssc_so.  A call to
5240Sstevel@tonic-gate 				 * sdssc_mo_create_begin will return with
5250Sstevel@tonic-gate 				 * either SDSSC_ERROR or SDSSC_OKAY. If
5260Sstevel@tonic-gate 				 * an SDSSC_OKAY is returned, then the
5270Sstevel@tonic-gate 				 * cluster framework has allocated a
5280Sstevel@tonic-gate 				 * set number for this new set that is unique
5290Sstevel@tonic-gate 				 * across traditional and MN disksets.
5300Sstevel@tonic-gate 				 * Libmeta will get this unique set number
5310Sstevel@tonic-gate 				 * by calling sdssc_get_index.
5320Sstevel@tonic-gate 				 *
5330Sstevel@tonic-gate 				 * When running on a non-cluster system,
5340Sstevel@tonic-gate 				 * the routine sdssc_mo_create_begin
5350Sstevel@tonic-gate 				 * will be bound to the SVM routine
5360Sstevel@tonic-gate 				 * not_bound which returns SDSSC_NOT_BOUND.
5370Sstevel@tonic-gate 				 * In this case, all sdssc routines will
5380Sstevel@tonic-gate 				 * return SDSSC_NOT_BOUND.  No need to check
5390Sstevel@tonic-gate 				 * for return value of SDSSC_NOT_BOUND since
5400Sstevel@tonic-gate 				 * the libmeta call to get the set number
5410Sstevel@tonic-gate 				 * (sdssc_get_index) will also fail with
5420Sstevel@tonic-gate 				 * SDSSC_NOT_BOUND causing libmeta to
5430Sstevel@tonic-gate 				 * determine its own set number.
5440Sstevel@tonic-gate 				 */
5450Sstevel@tonic-gate 				sdssc_rval = sdssc_mo_create_begin(sname, argc,
5460Sstevel@tonic-gate 					argv, SDSSC_PICK_SETNO);
5470Sstevel@tonic-gate 				if (sdssc_rval == SDSSC_NOT_BOUND_ERROR) {
5480Sstevel@tonic-gate 					mderror(ep, MDE_NOT_MN, NULL);
5490Sstevel@tonic-gate 					mde_perror(ep,
5500Sstevel@tonic-gate 					"Cluster node does not support "
5510Sstevel@tonic-gate 					"multi-owner diskset operations");
5520Sstevel@tonic-gate 					md_exit(local_sp, 1);
5530Sstevel@tonic-gate 				} else if (sdssc_rval == SDSSC_ERROR) {
5540Sstevel@tonic-gate 					mde_perror(ep, "");
5550Sstevel@tonic-gate 					md_exit(local_sp, 1);
5560Sstevel@tonic-gate 				}
5570Sstevel@tonic-gate 			} else {
5580Sstevel@tonic-gate 				sdssc_rval = sdssc_create_begin(sname, argc,
5590Sstevel@tonic-gate 					argv, SDSSC_PICK_SETNO);
5600Sstevel@tonic-gate 				if (sdssc_rval == SDSSC_ERROR) {
5610Sstevel@tonic-gate 					mde_perror(ep, "");
5620Sstevel@tonic-gate 					md_exit(local_sp, 1);
5630Sstevel@tonic-gate 				}
5640Sstevel@tonic-gate 			}
5650Sstevel@tonic-gate 			/*
5660Sstevel@tonic-gate 			 * Created diskset (as opposed to adding a
5670Sstevel@tonic-gate 			 * host to an existing diskset).
5680Sstevel@tonic-gate 			 */
5690Sstevel@tonic-gate 			created_set = 1;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 			sp = Zalloc(sizeof (*sp));
5720Sstevel@tonic-gate 			sp->setname = Strdup(sname);
5730Sstevel@tonic-gate 			sp->lockfd = MD_NO_LOCK;
5740Sstevel@tonic-gate 			mdclrerror(ep);
5750Sstevel@tonic-gate 		} else {
5760Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
5770Sstevel@tonic-gate 				mde_perror(ep, "");
5780Sstevel@tonic-gate 				md_exit(local_sp, 1);
5790Sstevel@tonic-gate 			}
5800Sstevel@tonic-gate 			if (MD_MNSET_DESC(sd)) {
5810Sstevel@tonic-gate 				multi_node = 1;
5820Sstevel@tonic-gate 			}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 			/*
5850Sstevel@tonic-gate 			 * can't add hosts to an existing set & enable
5860Sstevel@tonic-gate 			 * auto-take
5870Sstevel@tonic-gate 			 */
5880Sstevel@tonic-gate 			if (auto_take)
5890Sstevel@tonic-gate 				usage(sp, gettext("conflicting options"));
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 			/*
5920Sstevel@tonic-gate 			 * Have a valid set, take the set lock also.
5930Sstevel@tonic-gate 			 *
5940Sstevel@tonic-gate 			 * A MN diskset does not use the set meta_lock but
5950Sstevel@tonic-gate 			 * instead uses the clnt_lock of rpc.metad and the
5960Sstevel@tonic-gate 			 * suspend/resume feature of the rpc.mdcommd.  Can't
5970Sstevel@tonic-gate 			 * use set meta_lock since class 1 messages are
5980Sstevel@tonic-gate 			 * grabbing this lock and if this thread is holding
5990Sstevel@tonic-gate 			 * the set meta_lock then no rpc.mdcommd suspend
6000Sstevel@tonic-gate 			 * can occur.
6010Sstevel@tonic-gate 			 */
6020Sstevel@tonic-gate 			if (!multi_node) {
6030Sstevel@tonic-gate 				if (meta_lock(sp, TRUE, ep) != 0) {
6040Sstevel@tonic-gate 					mde_perror(ep, "");
6050Sstevel@tonic-gate 					md_exit(local_sp, 1);
6060Sstevel@tonic-gate 				}
6070Sstevel@tonic-gate 			}
6080Sstevel@tonic-gate 		}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 		if (meta_set_addhosts(sp, multi_node, argc, argv, auto_take,
6110Sstevel@tonic-gate 		    ep)) {
6120Sstevel@tonic-gate 			if (created_set)
6130Sstevel@tonic-gate 				sdssc_create_end(sname, SDSSC_CLEANUP);
6140Sstevel@tonic-gate 			mde_perror(&status, "");
6150Sstevel@tonic-gate 			if (!multi_node)
6160Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
6170Sstevel@tonic-gate 			md_exit(local_sp, 1);
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		if (created_set)
6210Sstevel@tonic-gate 			sdssc_create_end(sname, SDSSC_COMMIT);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		else {
6240Sstevel@tonic-gate 			/*
6250Sstevel@tonic-gate 			 * If adding hosts to existing diskset,
6260Sstevel@tonic-gate 			 * call DCS svcs
6270Sstevel@tonic-gate 			 */
6280Sstevel@tonic-gate 			sdssc_add_hosts(sname, argc, argv);
6290Sstevel@tonic-gate 		}
6300Sstevel@tonic-gate 		if (!multi_node)
6310Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
6320Sstevel@tonic-gate 		md_exit(local_sp, 0);
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	/*
6360Sstevel@tonic-gate 	 * Add mediators
6370Sstevel@tonic-gate 	 */
6380Sstevel@tonic-gate 	if (meds == TRUE) {
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) == NULL) {
6410Sstevel@tonic-gate 			mde_perror(ep, "");
6420Sstevel@tonic-gate 			md_exit(local_sp, 1);
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
6460Sstevel@tonic-gate 			mde_perror(ep, "");
6470Sstevel@tonic-gate 			md_exit(local_sp, 1);
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
6510Sstevel@tonic-gate 			mde_perror(ep, "");
6520Sstevel@tonic-gate 			md_exit(local_sp, 1);
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
6550Sstevel@tonic-gate 			multi_node = 1;
6560Sstevel@tonic-gate 		}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		if (meta_lock(local_sp, TRUE, ep) != 0) {
6590Sstevel@tonic-gate 			mde_perror(ep, "");
6600Sstevel@tonic-gate 			md_exit(local_sp, 1);
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 		/*
6630Sstevel@tonic-gate 		 * A MN diskset does not use the set meta_lock but
6640Sstevel@tonic-gate 		 * instead uses the clnt_lock of rpc.metad and the
6650Sstevel@tonic-gate 		 * suspend/resume feature of the rpc.mdcommd.  Can't
6660Sstevel@tonic-gate 		 * use set meta_lock since class 1 messages are
6670Sstevel@tonic-gate 		 * grabbing this lock and if this thread is holding
6680Sstevel@tonic-gate 		 * the set meta_lock then no rpc.mdcommd suspend
6690Sstevel@tonic-gate 		 * can occur.
6700Sstevel@tonic-gate 		 */
6710Sstevel@tonic-gate 		if (!multi_node) {
6720Sstevel@tonic-gate 			if (meta_lock(sp, TRUE, ep) != 0) {
6730Sstevel@tonic-gate 				mde_perror(ep, "");
6740Sstevel@tonic-gate 				md_exit(local_sp, 1);
6750Sstevel@tonic-gate 			}
6760Sstevel@tonic-gate 		}
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 		if (meta_set_addmeds(sp, argc, argv, ep)) {
6790Sstevel@tonic-gate 			mde_perror(&status, "");
6800Sstevel@tonic-gate 			if (!multi_node)
6810Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
6820Sstevel@tonic-gate 			md_exit(local_sp, 1);
6830Sstevel@tonic-gate 		}
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 		if (!multi_node)
6860Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
6870Sstevel@tonic-gate 		md_exit(local_sp, 0);
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	/*
6910Sstevel@tonic-gate 	 * Add drives
6920Sstevel@tonic-gate 	 */
6930Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
6940Sstevel@tonic-gate 		mde_perror(ep, "");
6950Sstevel@tonic-gate 		md_exit(local_sp, 1);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
6990Sstevel@tonic-gate 		mde_perror(ep, "");
7000Sstevel@tonic-gate 		md_exit(local_sp, 1);
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	/* Determine if diskset is a MN diskset or not */
7040Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
7050Sstevel@tonic-gate 		mde_perror(ep, "");
7060Sstevel@tonic-gate 		md_exit(local_sp, 1);
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
7090Sstevel@tonic-gate 		multi_node = 1;
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
7130Sstevel@tonic-gate 		mde_perror(ep, "");
7140Sstevel@tonic-gate 		md_exit(local_sp, 1);
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/* Make sure database size is within limits */
7180Sstevel@tonic-gate 	if (default_size == FALSE) {
7190Sstevel@tonic-gate 		if ((multi_node && dbsize < MDDB_MN_MINBLKS) ||
7200Sstevel@tonic-gate 		    (!multi_node && dbsize < MDDB_MINBLKS))
7210Sstevel@tonic-gate 			usage(sp, gettext(
7220Sstevel@tonic-gate 			    "size (-l) is too small"));
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 		if ((multi_node && dbsize > MDDB_MN_MAXBLKS) ||
7250Sstevel@tonic-gate 		    (!multi_node && dbsize > MDDB_MAXBLKS))
7260Sstevel@tonic-gate 			usage(sp, gettext(
7270Sstevel@tonic-gate 			    "size (-l) is too big"));
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	/*
7310Sstevel@tonic-gate 	 * Have a valid set, take the set lock also.
7320Sstevel@tonic-gate 	 *
7330Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but
7340Sstevel@tonic-gate 	 * instead uses the clnt_lock of rpc.metad and the
7350Sstevel@tonic-gate 	 * suspend/resume feature of the rpc.mdcommd.  Can't
7360Sstevel@tonic-gate 	 * use set meta_lock since class 1 messages are
7370Sstevel@tonic-gate 	 * grabbing this lock and if this thread is holding
7380Sstevel@tonic-gate 	 * the set meta_lock then no rpc.mdcommd suspend
7390Sstevel@tonic-gate 	 * can occur.
7400Sstevel@tonic-gate 	 */
7410Sstevel@tonic-gate 	if (!multi_node) {
7420Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, ep) != 0) {
7430Sstevel@tonic-gate 			mde_perror(ep, "");
7440Sstevel@tonic-gate 			md_exit(local_sp, 1);
7450Sstevel@tonic-gate 		}
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * If using the default size,
7510Sstevel@tonic-gate 	 *   then let's adjust the default to the minimum
7520Sstevel@tonic-gate 	 *   size currently in use.
7530Sstevel@tonic-gate 	 */
7540Sstevel@tonic-gate 	if (default_size) {
7550Sstevel@tonic-gate 		dbsize = multi_node ? MD_MN_DBSIZE : MD_DBSIZE;
7560Sstevel@tonic-gate 		if ((nblks = meta_db_minreplica(sp, ep)) < 0)
7570Sstevel@tonic-gate 			mdclrerror(ep);
7580Sstevel@tonic-gate 		else
7590Sstevel@tonic-gate 			dbsize = nblks;	/* adjust replica size */
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) {
7630Sstevel@tonic-gate 		mde_perror(ep, "");
7640Sstevel@tonic-gate 		if (!multi_node)
7650Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
7660Sstevel@tonic-gate 		md_exit(local_sp, 1);
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	if (c == 0) {
7700Sstevel@tonic-gate 		md_perror(gettext(
7710Sstevel@tonic-gate 		    "No drives specified to add.\n"));
7720Sstevel@tonic-gate 		if (!multi_node)
7730Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
7740Sstevel@tonic-gate 		md_exit(local_sp, 1);
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	if (meta_set_adddrives(sp, dnlp, dbsize, force_label, ep)) {
7780Sstevel@tonic-gate 		metafreedrivenamelist(dnlp);
7790Sstevel@tonic-gate 		mde_perror(ep, "");
7800Sstevel@tonic-gate 		if (!multi_node)
7810Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
7820Sstevel@tonic-gate 		md_exit(local_sp, 1);
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	/*
7860Sstevel@tonic-gate 	 * MN disksets don't have a device id in the master block
7870Sstevel@tonic-gate 	 * For traditional disksets, check for the drive device
7880Sstevel@tonic-gate 	 * id not fitting in the master block
7890Sstevel@tonic-gate 	 */
7900Sstevel@tonic-gate 	if (!multi_node) {
7910Sstevel@tonic-gate 		for (p = dnlp; p != NULL; p = p->next) {
7920Sstevel@tonic-gate 			int 		fd;
7930Sstevel@tonic-gate 			ddi_devid_t	devid;
7940Sstevel@tonic-gate 			mdname_t	*np;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 			np = metaslicename(p->drivenamep, 0, ep);
7970Sstevel@tonic-gate 			if (np == NULL)
7980Sstevel@tonic-gate 				continue;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 			if ((fd = open(np->rname, O_RDONLY | O_NDELAY)) < 0)
8010Sstevel@tonic-gate 				continue;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 			if (devid_get(fd, &devid) == 0) {
8040Sstevel@tonic-gate 				size_t len;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 				len = devid_sizeof(devid);
8070Sstevel@tonic-gate 				if (len > (DEV_BSIZE - sizeof (mddb_mb_t)))
8080Sstevel@tonic-gate 					(void) mddserror(ep,
8090Sstevel@tonic-gate 					    MDE_DS_NOTSELFIDENTIFY, NULL, NULL,
8100Sstevel@tonic-gate 					    np->rname, NULL);
8110Sstevel@tonic-gate 				devid_free(devid);
8120Sstevel@tonic-gate 			} else {
8130Sstevel@tonic-gate 				(void) mddserror(ep, MDE_DS_NOTSELFIDENTIFY,
8140Sstevel@tonic-gate 				    NULL, NULL, np->rname, NULL);
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 			(void) close(fd);
8170Sstevel@tonic-gate 		}
8180Sstevel@tonic-gate 	}
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * MN disksets don't use DCS clustering services.
8220Sstevel@tonic-gate 	 * For traditional disksets:
8230Sstevel@tonic-gate 	 * There's not really much we can do here if this call fails.
8240Sstevel@tonic-gate 	 * The drives have been added to the set and DiskSuite believes
8250Sstevel@tonic-gate 	 * it owns the drives.
8260Sstevel@tonic-gate 	 * Relase the set and hope for the best.
8270Sstevel@tonic-gate 	 */
8280Sstevel@tonic-gate 	if ((!multi_node) &&
8290Sstevel@tonic-gate 	    (sdssc_notify_service(sname, Make_Primary) == SDSSC_ERROR)) {
8300Sstevel@tonic-gate 		meta_set_release(sp, ep);
8310Sstevel@tonic-gate 		printf(gettext(
8320Sstevel@tonic-gate 		    "Sun Clustering failed to make set primary\n"));
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	metafreedrivenamelist(dnlp);
8360Sstevel@tonic-gate 	if (!multi_node)
8370Sstevel@tonic-gate 		(void) meta_unlock(sp, ep);
8380Sstevel@tonic-gate 	md_exit(local_sp, 0);
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate static void
8420Sstevel@tonic-gate parse_balance(int argc, char **argv)
8430Sstevel@tonic-gate {
8440Sstevel@tonic-gate 	int		c;
8450Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
8460Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
8470Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
8480Sstevel@tonic-gate 	md_set_desc	*sd;
8490Sstevel@tonic-gate 	int		multi_node = 0;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	/* reset and parse args */
8520Sstevel@tonic-gate 	optind = 1;
8530Sstevel@tonic-gate 	opterr = 1;
8540Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Mbs:")) != -1) {
8550Sstevel@tonic-gate 		switch (c) {
8560Sstevel@tonic-gate 		case 'M':
8570Sstevel@tonic-gate 			break;
8580Sstevel@tonic-gate 		case 'b':
8590Sstevel@tonic-gate 			break;
8600Sstevel@tonic-gate 		case 's':
8610Sstevel@tonic-gate 			sname = optarg;
8620Sstevel@tonic-gate 			break;
8630Sstevel@tonic-gate 		default:
8640Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
8650Sstevel@tonic-gate 		}
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	argc -= optind;
8690Sstevel@tonic-gate 	argv += optind;
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	if (argc != 0)
8720Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	if ((sp = metasetname(sname, &status)) == NULL) {
8750Sstevel@tonic-gate 		mde_perror(&status, "");
8760Sstevel@tonic-gate 		md_exit(sp, 1);
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, &status)) == NULL) {
8790Sstevel@tonic-gate 		mde_perror(&status, "");
8800Sstevel@tonic-gate 		md_exit(sp, 1);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
8830Sstevel@tonic-gate 		multi_node = 1;
8840Sstevel@tonic-gate 	}
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * Have a valid set, take the set lock also.
8870Sstevel@tonic-gate 	 *
8880Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but
8890Sstevel@tonic-gate 	 * instead uses the clnt_lock of rpc.metad and the
8900Sstevel@tonic-gate 	 * suspend/resume feature of the rpc.mdcommd.  Can't
8910Sstevel@tonic-gate 	 * use set meta_lock since class 1 messages are
8920Sstevel@tonic-gate 	 * grabbing this lock and if this thread is holding
8930Sstevel@tonic-gate 	 * the set meta_lock then no rpc.mdcommd suspend
8940Sstevel@tonic-gate 	 * can occur.
8950Sstevel@tonic-gate 	 */
8960Sstevel@tonic-gate 	if (!multi_node) {
8970Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, &status) != 0) {
8980Sstevel@tonic-gate 			mde_perror(&status, "");
8990Sstevel@tonic-gate 			md_exit(sp, 1);
9000Sstevel@tonic-gate 		}
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	if (meta_set_balance(sp, &status) != 0) {
9040Sstevel@tonic-gate 		mde_perror(&status, "");
9050Sstevel@tonic-gate 		md_exit(sp, 1);
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 	md_exit(sp, 0);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate static void
9110Sstevel@tonic-gate parse_autotake(int argc, char **argv)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate 	int			c;
9140Sstevel@tonic-gate 	int			enable = 0;
9150Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
9160Sstevel@tonic-gate 	char			*sname = MD_LOCAL_NAME;
9170Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
9180Sstevel@tonic-gate 	md_error_t		*ep = &status;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	/* reset and parse args */
9210Sstevel@tonic-gate 	optind = 1;
9220Sstevel@tonic-gate 	opterr = 1;
9230Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "A:s:")) != -1) {
9240Sstevel@tonic-gate 		switch (c) {
9250Sstevel@tonic-gate 		case 'A':
9260Sstevel@tonic-gate 			/* verified sub-option in main */
9270Sstevel@tonic-gate 			if (strcmp(optarg, "enable") == 0)
9280Sstevel@tonic-gate 				enable = 1;
9290Sstevel@tonic-gate 			break;
9300Sstevel@tonic-gate 		case 's':
9310Sstevel@tonic-gate 			/* verified presence of setname in main */
9320Sstevel@tonic-gate 			sname = optarg;
9330Sstevel@tonic-gate 			break;
9340Sstevel@tonic-gate 		default:
9350Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
9360Sstevel@tonic-gate 		}
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
9400Sstevel@tonic-gate 		mde_perror(ep, "");
9410Sstevel@tonic-gate 		md_exit(sp, 1);
9420Sstevel@tonic-gate 	}
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, ep) != 0) {
9450Sstevel@tonic-gate 		mde_perror(ep, "");
9460Sstevel@tonic-gate 		md_exit(sp, 1);
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) != 0) {
9500Sstevel@tonic-gate 		mde_perror(ep, "");
9510Sstevel@tonic-gate 		md_exit(sp, 1);
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	if (meta_set_auto_take(sp, enable, ep) != 0) {
9550Sstevel@tonic-gate 		mde_perror(ep, "");
9560Sstevel@tonic-gate 		md_exit(sp, 1);
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	md_exit(sp, 0);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate static void
9630Sstevel@tonic-gate parse_del(int argc, char **argv)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate 	int			c;
9660Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
9670Sstevel@tonic-gate 	char			*sname = MD_LOCAL_NAME;
9680Sstevel@tonic-gate 	int			hosts = FALSE;
9690Sstevel@tonic-gate 	int			meds = FALSE;
9700Sstevel@tonic-gate 	int			forceflg = FALSE;
9710Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
9720Sstevel@tonic-gate 	md_error_t		*ep = &status;
9730Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
9740Sstevel@tonic-gate 	mdsetname_t		*local_sp = NULL;
9750Sstevel@tonic-gate 	md_set_desc		*sd;
9760Sstevel@tonic-gate 	int			multi_node = 0;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	/* reset and parse args */
9790Sstevel@tonic-gate 	optind = 1;
9800Sstevel@tonic-gate 	opterr = 1;
9810Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Mdfhms:")) != -1) {
9820Sstevel@tonic-gate 		switch (c) {
9830Sstevel@tonic-gate 		case 'M':
9840Sstevel@tonic-gate 			break;
9850Sstevel@tonic-gate 		case 'd':
9860Sstevel@tonic-gate 			break;
9870Sstevel@tonic-gate 		case 'f':
9880Sstevel@tonic-gate 			forceflg = TRUE;
9890Sstevel@tonic-gate 			break;
9900Sstevel@tonic-gate 		case 'h':
9910Sstevel@tonic-gate 		case 'm':
9920Sstevel@tonic-gate 			if (meds == TRUE || hosts == TRUE)
9930Sstevel@tonic-gate 				usage(sp, gettext(
9940Sstevel@tonic-gate 				    "only one -m or -h option allowed"));
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 			if (c == 'h')
9970Sstevel@tonic-gate 				hosts = TRUE;
9980Sstevel@tonic-gate 			else
9990Sstevel@tonic-gate 				meds = TRUE;
10000Sstevel@tonic-gate 			break;
10010Sstevel@tonic-gate 		case 's':
10020Sstevel@tonic-gate 			sname = optarg;
10030Sstevel@tonic-gate 			break;
10040Sstevel@tonic-gate 		default:
10050Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
10060Sstevel@tonic-gate 		}
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	argc -= optind;
10100Sstevel@tonic-gate 	argv += optind;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
10130Sstevel@tonic-gate 		mde_perror(ep, "");
10140Sstevel@tonic-gate 		md_exit(local_sp, 1);
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
10180Sstevel@tonic-gate 		mde_perror(ep, "");
10190Sstevel@tonic-gate 		md_exit(local_sp, 1);
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
10230Sstevel@tonic-gate 		mde_perror(ep, "");
10240Sstevel@tonic-gate 		md_exit(local_sp, 1);
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd))
10270Sstevel@tonic-gate 		multi_node = 1;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
10300Sstevel@tonic-gate 		mde_perror(ep, "");
10310Sstevel@tonic-gate 		md_exit(local_sp, 1);
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	/*
10350Sstevel@tonic-gate 	 * Have a valid set, take the set lock also.
10360Sstevel@tonic-gate 	 *
10370Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but
10380Sstevel@tonic-gate 	 * instead uses the clnt_lock of rpc.metad and the
10390Sstevel@tonic-gate 	 * suspend/resume feature of the rpc.mdcommd.  Can't
10400Sstevel@tonic-gate 	 * use set meta_lock since class 1 messages are
10410Sstevel@tonic-gate 	 * grabbing this lock and if this thread is holding
10420Sstevel@tonic-gate 	 * the set meta_lock then no rpc.mdcommd suspend
10430Sstevel@tonic-gate 	 * can occur.
10440Sstevel@tonic-gate 	 */
10450Sstevel@tonic-gate 	if (!multi_node) {
10460Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, ep) != 0) {
10470Sstevel@tonic-gate 			mde_perror(ep, "");
10480Sstevel@tonic-gate 			md_exit(local_sp, 1);
10490Sstevel@tonic-gate 		}
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	/*
10530Sstevel@tonic-gate 	 * Delete hosts
10540Sstevel@tonic-gate 	 */
10550Sstevel@tonic-gate 	if (hosts == TRUE) {
10560Sstevel@tonic-gate 		if (meta_check_ownership(sp, ep) != 0) {
10570Sstevel@tonic-gate 			/*
10580Sstevel@tonic-gate 			 * If we don't own the set bail out here otherwise
10590Sstevel@tonic-gate 			 * we could delete the node from the DCS service
10600Sstevel@tonic-gate 			 * yet not delete the host from the set.
10610Sstevel@tonic-gate 			 */
10620Sstevel@tonic-gate 			mde_perror(ep, "");
10630Sstevel@tonic-gate 			if (!multi_node)
10640Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
10650Sstevel@tonic-gate 			md_exit(local_sp, 1);
10660Sstevel@tonic-gate 		}
10670Sstevel@tonic-gate 		if (sdssc_delete_hosts(sname, argc, argv) == SDSSC_ERROR) {
10680Sstevel@tonic-gate 		    if (!metad_isautotakebyname(sname)) {
10690Sstevel@tonic-gate 			/*
10700Sstevel@tonic-gate 			 * SC could have been installed after the set was
10710Sstevel@tonic-gate 			 * created.  We still want to be able to delete these
10720Sstevel@tonic-gate 			 * sets.
10730Sstevel@tonic-gate 			 */
10740Sstevel@tonic-gate 			md_perror(gettext(
10750Sstevel@tonic-gate 			    "Failed to delete hosts from DCS service"));
10760Sstevel@tonic-gate 			if (!multi_node)
10770Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
10780Sstevel@tonic-gate 			md_exit(local_sp, 1);
10790Sstevel@tonic-gate 		    }
10800Sstevel@tonic-gate 		}
10810Sstevel@tonic-gate 		if (meta_set_deletehosts(sp, argc, argv, forceflg, ep)) {
10820Sstevel@tonic-gate 			if (sdssc_add_hosts(sname, argc, argv) == SDSSC_ERROR) {
10830Sstevel@tonic-gate 				(void) printf(gettext(
10840Sstevel@tonic-gate 				    "Failed to restore host(s) in DCS "
10850Sstevel@tonic-gate 				    "database\n"));
10860Sstevel@tonic-gate 			}
10870Sstevel@tonic-gate 			mde_perror(ep, "");
10880Sstevel@tonic-gate 			if (!multi_node)
10890Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
10900Sstevel@tonic-gate 			md_exit(local_sp, 1);
10910Sstevel@tonic-gate 		}
10920Sstevel@tonic-gate 		if (!multi_node)
10930Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
10940Sstevel@tonic-gate 		md_exit(local_sp, 0);
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	/*
10980Sstevel@tonic-gate 	 * Delete mediators
10990Sstevel@tonic-gate 	 */
11000Sstevel@tonic-gate 	if (meds == TRUE) {
11010Sstevel@tonic-gate 		if (meta_set_deletemeds(sp, argc, argv, forceflg, ep)) {
11020Sstevel@tonic-gate 			mde_perror(ep, "");
11030Sstevel@tonic-gate 			if (!multi_node)
11040Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
11050Sstevel@tonic-gate 			md_exit(local_sp, 1);
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 		if (!multi_node)
11080Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
11090Sstevel@tonic-gate 		md_exit(local_sp, 0);
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	/*
11130Sstevel@tonic-gate 	 * Delete drives
11140Sstevel@tonic-gate 	 */
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) {
11170Sstevel@tonic-gate 		mde_perror(ep, "");
11180Sstevel@tonic-gate 		if (!multi_node)
11190Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
11200Sstevel@tonic-gate 		md_exit(local_sp, 1);
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	if (c == 0) {
11240Sstevel@tonic-gate 		md_perror(gettext(
11250Sstevel@tonic-gate 		    "No drives specified to delete.\n"));
11260Sstevel@tonic-gate 		if (!multi_node)
11270Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
11280Sstevel@tonic-gate 		md_exit(local_sp, 1);
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	if (meta_set_deletedrives(sp, dnlp, forceflg, ep)) {
11320Sstevel@tonic-gate 		metafreedrivenamelist(dnlp);
11330Sstevel@tonic-gate 		mde_perror(ep, "");
11340Sstevel@tonic-gate 		if (!multi_node)
11350Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
11360Sstevel@tonic-gate 		md_exit(local_sp, 1);
11370Sstevel@tonic-gate 	}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	metafreedrivenamelist(dnlp);
11400Sstevel@tonic-gate 	if (!multi_node)
11410Sstevel@tonic-gate 		(void) meta_unlock(sp, ep);
11420Sstevel@tonic-gate 	md_exit(local_sp, 0);
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate static void
11460Sstevel@tonic-gate parse_isowner(int argc, char **argv)
11470Sstevel@tonic-gate {
11480Sstevel@tonic-gate 	int		c;
11490Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
11500Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
11510Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
11520Sstevel@tonic-gate 	md_error_t	*ep = &status;
11530Sstevel@tonic-gate 	char		*host = NULL;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/* reset and parse args */
11560Sstevel@tonic-gate 	optind = 1;
11570Sstevel@tonic-gate 	opterr = 1;
11580Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Moh:s:")) != -1) {
11590Sstevel@tonic-gate 		switch (c) {
11600Sstevel@tonic-gate 		case 'M':
11610Sstevel@tonic-gate 			break;
11620Sstevel@tonic-gate 		case 'o':
11630Sstevel@tonic-gate 			break;
11640Sstevel@tonic-gate 		case 'h':
11650Sstevel@tonic-gate 			if (host != NULL) {
11660Sstevel@tonic-gate 				usage(sp, gettext(
11670Sstevel@tonic-gate 				    "only one -h option allowed"));
11680Sstevel@tonic-gate 			}
11690Sstevel@tonic-gate 			host = optarg;
11700Sstevel@tonic-gate 			break;
11710Sstevel@tonic-gate 		case 's':
11720Sstevel@tonic-gate 			sname = optarg;
11730Sstevel@tonic-gate 			break;
11740Sstevel@tonic-gate 		default:
11750Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	argc -= optind;
11800Sstevel@tonic-gate 	argv += optind;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	if (argc != 0)
11830Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
11860Sstevel@tonic-gate 		mde_perror(ep, "");
11870Sstevel@tonic-gate 		md_exit(sp, 1);
11880Sstevel@tonic-gate 	}
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	if (host == NULL) {
11910Sstevel@tonic-gate 		if (meta_check_ownership(sp, ep) != 0) {
11920Sstevel@tonic-gate 			mde_perror(ep, "");
11930Sstevel@tonic-gate 			md_exit(sp, 1);
11940Sstevel@tonic-gate 		}
11950Sstevel@tonic-gate 	} else {
11960Sstevel@tonic-gate 		if (meta_check_ownership_on_host(sp, host, ep) != 0) {
11970Sstevel@tonic-gate 			mde_perror(ep, "");
11980Sstevel@tonic-gate 			md_exit(sp, 1);
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 	}
12010Sstevel@tonic-gate 	md_exit(sp, 0);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate static void
12050Sstevel@tonic-gate parse_purge(int argc, char **argv)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	int		c;
12080Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
12090Sstevel@tonic-gate 	mdsetname_t	*local_sp = NULL;
12100Sstevel@tonic-gate 	md_drive_desc	*dd;
12110Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
12120Sstevel@tonic-gate 	char		*thishost = mynode();
12130Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
12140Sstevel@tonic-gate 	md_error_t	*ep = &status;
12150Sstevel@tonic-gate 	int		bypass_cluster_purge = 0;
12160Sstevel@tonic-gate 	int		forceflg = FALSE;
12170Sstevel@tonic-gate 	int		ret = 0;
12180Sstevel@tonic-gate 	int		multi_node = 0;
12190Sstevel@tonic-gate 	md_set_desc		*sd;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	optind = 1;
12220Sstevel@tonic-gate 	opterr = 1;
12230Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "C:fPs:")) != -1) {
12240Sstevel@tonic-gate 		switch (c) {
12250Sstevel@tonic-gate 		case 'M':
12260Sstevel@tonic-gate 			break;
12270Sstevel@tonic-gate 		case 'C':
12280Sstevel@tonic-gate 			bypass_cluster_purge = 1;
12290Sstevel@tonic-gate 			break;
12300Sstevel@tonic-gate 		case 'f':
12310Sstevel@tonic-gate 			forceflg = TRUE;
12320Sstevel@tonic-gate 			break;
12330Sstevel@tonic-gate 		case 'P':
12340Sstevel@tonic-gate 			break;
12350Sstevel@tonic-gate 		case 's':
12360Sstevel@tonic-gate 			sname = optarg;
12370Sstevel@tonic-gate 			break;
12380Sstevel@tonic-gate 		default:
12390Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate 	}
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	argc -= optind;
12440Sstevel@tonic-gate 	argv += optind;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	if (argc != 0)
12470Sstevel@tonic-gate 		usage(sp, gettext("too many arguments"));
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
12500Sstevel@tonic-gate 		mde_perror(ep, "");
12510Sstevel@tonic-gate 		md_exit(local_sp, 1);
12520Sstevel@tonic-gate 	}
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
12550Sstevel@tonic-gate 		mde_perror(ep, "");
12560Sstevel@tonic-gate 		md_exit(local_sp, 1);
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
12600Sstevel@tonic-gate 		mde_perror(ep, "");
12610Sstevel@tonic-gate 		md_exit(sp, 1);
12620Sstevel@tonic-gate 	}
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
12650Sstevel@tonic-gate 		mde_perror(ep, "");
12660Sstevel@tonic-gate 		md_exit(local_sp, 1);
12670Sstevel@tonic-gate 	}
12680Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd))
12690Sstevel@tonic-gate 		multi_node = 1;
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 	if (!multi_node) {
12720Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, ep) != 0) {
12730Sstevel@tonic-gate 			mde_perror(ep, "");
12740Sstevel@tonic-gate 			md_exit(local_sp, 1);
12750Sstevel@tonic-gate 		}
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	/* Must not own the set if purging it from this host */
12790Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) == 0) {
12800Sstevel@tonic-gate 		/*
12810Sstevel@tonic-gate 		 * Need to see if there are disks in the set, if not then
12820Sstevel@tonic-gate 		 * there is no ownership but meta_check_ownership returns 0
12830Sstevel@tonic-gate 		 */
12840Sstevel@tonic-gate 		dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST), ep);
12850Sstevel@tonic-gate 		if (!mdisok(ep)) {
12860Sstevel@tonic-gate 			mde_perror(ep, "");
12870Sstevel@tonic-gate 			if (!multi_node)
12880Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
12890Sstevel@tonic-gate 			md_exit(local_sp, 1);
12900Sstevel@tonic-gate 		}
12910Sstevel@tonic-gate 		if (dd != NULL) {
12920Sstevel@tonic-gate 			(void) printf(gettext
12930Sstevel@tonic-gate 			    ("Must not be owner of the set when purging it\n"));
12940Sstevel@tonic-gate 			if (!multi_node)
12950Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
12960Sstevel@tonic-gate 			md_exit(local_sp, 1);
12970Sstevel@tonic-gate 		}
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 	/*
13000Sstevel@tonic-gate 	 * Remove the node from the DCS service
13010Sstevel@tonic-gate 	 */
13020Sstevel@tonic-gate 	if (!bypass_cluster_purge) {
13030Sstevel@tonic-gate 		if (sdssc_delete_hosts(sname, 1, &thishost) == SDSSC_ERROR) {
13040Sstevel@tonic-gate 			md_perror(gettext
13050Sstevel@tonic-gate 			    ("Failed to purge hosts from DCS service"));
13060Sstevel@tonic-gate 			if (!multi_node)
13070Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
13080Sstevel@tonic-gate 			md_exit(local_sp, 1);
13090Sstevel@tonic-gate 		}
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	if ((ret = meta_set_purge(sp, bypass_cluster_purge, forceflg,
13130Sstevel@tonic-gate 	    ep)) != 0) {
13140Sstevel@tonic-gate 		if (!bypass_cluster_purge) {
13150Sstevel@tonic-gate 			if (sdssc_add_hosts(sname, 1, &thishost) ==
13160Sstevel@tonic-gate 			    SDSSC_ERROR) {
13170Sstevel@tonic-gate 				(void) printf(gettext(
13180Sstevel@tonic-gate 				    "Failed to restore host in DCS "
13190Sstevel@tonic-gate 				    "database\n"));
13200Sstevel@tonic-gate 			}
13210Sstevel@tonic-gate 		}
13220Sstevel@tonic-gate 		mde_perror(ep, "");
13230Sstevel@tonic-gate 		if (!multi_node)
13240Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
13250Sstevel@tonic-gate 		md_exit(local_sp, ret);
13260Sstevel@tonic-gate 	}
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	if (!multi_node)
13290Sstevel@tonic-gate 		(void) meta_unlock(sp, ep);
13300Sstevel@tonic-gate 	md_exit(local_sp, 0);
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate static void
13340Sstevel@tonic-gate parse_query(int argc, char **argv)
13350Sstevel@tonic-gate {
13360Sstevel@tonic-gate 	int		c;
13370Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
13380Sstevel@tonic-gate 	mddb_dtag_lst_t	*dtlp = NULL;
13390Sstevel@tonic-gate 	mddb_dtag_lst_t	*tdtlp;
13400Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
13410Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/* reset and parse args */
13440Sstevel@tonic-gate 	optind = 1;
13450Sstevel@tonic-gate 	opterr = 1;
13460Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Mqs:")) != -1) {
13470Sstevel@tonic-gate 		switch (c) {
13480Sstevel@tonic-gate 		case 'M':
13490Sstevel@tonic-gate 			break;
13500Sstevel@tonic-gate 		case 'q':
13510Sstevel@tonic-gate 			break;
13520Sstevel@tonic-gate 		case 's':
13530Sstevel@tonic-gate 			sname = optarg;
13540Sstevel@tonic-gate 			break;
13550Sstevel@tonic-gate 		default:
13560Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
13570Sstevel@tonic-gate 		}
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	argc -= optind;
13610Sstevel@tonic-gate 	argv += optind;
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	if (argc != 0)
13640Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	if ((sp = metasetname(sname, &status)) == NULL) {
13670Sstevel@tonic-gate 		mde_perror(&status, "");
13680Sstevel@tonic-gate 		md_exit(sp, 1);
13690Sstevel@tonic-gate 	}
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, &status) != 0) {
13720Sstevel@tonic-gate 		mde_perror(&status, "");
13730Sstevel@tonic-gate 		md_exit(sp, 1);
13740Sstevel@tonic-gate 	}
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	if (meta_set_query(sp, &dtlp, &status) != 0) {
13770Sstevel@tonic-gate 		mde_perror(&status, "");
13780Sstevel@tonic-gate 		md_exit(sp, 1);
13790Sstevel@tonic-gate 	}
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	if (dtlp != NULL)
13820Sstevel@tonic-gate 		(void) printf("The following tag(s) were found:\n");
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	for (tdtlp = dtlp; tdtlp != NULL; tdtlp = dtlp) {
13850Sstevel@tonic-gate 		dtlp = tdtlp->dtl_nx;
13860Sstevel@tonic-gate 		(void) printf("%2d - %s - %s", tdtlp->dtl_dt.dt_id,
13870Sstevel@tonic-gate 		    tdtlp->dtl_dt.dt_hn,
13880Sstevel@tonic-gate 		    ctime((long *)&tdtlp->dtl_dt.dt_tv.tv_sec));
13890Sstevel@tonic-gate 		Free(tdtlp);
13900Sstevel@tonic-gate 	}
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	md_exit(sp, 0);
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate /* Should never be called with sname of a Multinode diskset. */
13960Sstevel@tonic-gate static void
13970Sstevel@tonic-gate parse_releaseset(int argc, char **argv)
13980Sstevel@tonic-gate {
13990Sstevel@tonic-gate 	int		c;
14000Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
14010Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
14020Sstevel@tonic-gate 	md_error_t	*ep = &status;
14030Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
14040Sstevel@tonic-gate 	sdssc_boolean_e	cluster_release = SDSSC_False;
14050Sstevel@tonic-gate 	sdssc_version_t	vers;
14060Sstevel@tonic-gate 	rval_e		rval;
14070Sstevel@tonic-gate 	md_set_desc	*sd;
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	/* reset and parse args */
14100Sstevel@tonic-gate 	optind = 1;
14110Sstevel@tonic-gate 	opterr = 1;
14121320Srd117015 	while ((c = getopt(argc, argv, "C:s:r")) != -1) {
14130Sstevel@tonic-gate 		switch (c) {
14140Sstevel@tonic-gate 		case 'C':
14150Sstevel@tonic-gate 			cluster_release = SDSSC_True;
14160Sstevel@tonic-gate 			break;
14170Sstevel@tonic-gate 		case 's':
14180Sstevel@tonic-gate 			sname = optarg;
14190Sstevel@tonic-gate 			break;
14200Sstevel@tonic-gate 		case 'r':
14210Sstevel@tonic-gate 			break;
14220Sstevel@tonic-gate 		default:
14230Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
14240Sstevel@tonic-gate 		}
14250Sstevel@tonic-gate 	}
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 	argc -= optind;
14280Sstevel@tonic-gate 	argv += optind;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	if (argc > 0)
14310Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	memset(&vers, 0, sizeof (vers));
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	if ((sdssc_version(&vers) == SDSSC_OKAY) &&
14360Sstevel@tonic-gate 	    (vers.major == 3) &&
14370Sstevel@tonic-gate 	    (cluster_release == SDSSC_False)) {
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 		/*
14400Sstevel@tonic-gate 		 * If the release is being done by the user via the CLI
14410Sstevel@tonic-gate 		 * we need to notify the DCS to release this node as being
14420Sstevel@tonic-gate 		 * the primary. The reason nothing else needs to be done
14430Sstevel@tonic-gate 		 * is due to the fact that the reservation code will exec
14440Sstevel@tonic-gate 		 * metaset -C release to complete the operation.
14450Sstevel@tonic-gate 		 */
14460Sstevel@tonic-gate 		rval = sdssc_notify_service(sname, Release_Primary);
14470Sstevel@tonic-gate 		if (rval == SDSSC_ERROR) {
14480Sstevel@tonic-gate 			printf(gettext(
14490Sstevel@tonic-gate 			    "metaset: failed to notify DCS of release\n"));
14500Sstevel@tonic-gate 		}
14510Sstevel@tonic-gate 		md_exit(NULL, rval == SDSSC_ERROR);
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 		/*
14570Sstevel@tonic-gate 		 * It's entirely possible for the SC3.0 reservation code
14580Sstevel@tonic-gate 		 * to call for DiskSet to release a diskset and have that
14590Sstevel@tonic-gate 		 * diskset not exist. During a diskset removal DiskSuite
14600Sstevel@tonic-gate 		 * maybe able to remove all traces of the diskset before
14610Sstevel@tonic-gate 		 * the reservation code execs metaset -C release in which
14620Sstevel@tonic-gate 		 * case the metasetname will fail, but the overall command
14630Sstevel@tonic-gate 		 * shouldn't.
14640Sstevel@tonic-gate 		 */
14650Sstevel@tonic-gate 		if (vers.major == 3)
14660Sstevel@tonic-gate 			md_exit(sp, 0);
14670Sstevel@tonic-gate 		else {
14680Sstevel@tonic-gate 			mde_perror(ep, "");
14690Sstevel@tonic-gate 			md_exit(sp, 1);
14700Sstevel@tonic-gate 		}
14710Sstevel@tonic-gate 	}
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
14740Sstevel@tonic-gate 		mde_perror(ep, "");
14750Sstevel@tonic-gate 		md_exit(sp, 1);
14760Sstevel@tonic-gate 	}
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	if (sd->sd_flags & MD_SR_AUTO_TAKE) {
14790Sstevel@tonic-gate 		md_eprintf(gettext("cannot release auto-take diskset\n"));
14800Sstevel@tonic-gate 		md_exit(sp, 1);
14810Sstevel@tonic-gate 	}
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
14841320Srd117015 		mde_perror(ep, "");
14851320Srd117015 		md_exit(sp, 10);	/* special errcode */
14860Sstevel@tonic-gate 	}
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	if (meta_set_release(sp, ep)) {
14890Sstevel@tonic-gate 		mde_perror(ep, "");
14900Sstevel@tonic-gate 		md_exit(sp, 1);
14910Sstevel@tonic-gate 	}
14920Sstevel@tonic-gate 	md_exit(sp, 0);
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate /* Should never be called with sname of a Multinode diskset. */
14960Sstevel@tonic-gate static void
14970Sstevel@tonic-gate parse_takeset(int argc, char **argv)
14980Sstevel@tonic-gate {
14990Sstevel@tonic-gate 	int		c;
15000Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
15010Sstevel@tonic-gate 	int		flags = 0;
15020Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
15030Sstevel@tonic-gate 	mhd_mhiargs_t	mhiargs;
15040Sstevel@tonic-gate 	char 		*cp = NULL;
15050Sstevel@tonic-gate 	int		pos = -1;	/* position of timeout value */
15060Sstevel@tonic-gate 	int		usetag = 0;
15070Sstevel@tonic-gate 	static char	*nullopts[] = { NULL };
15080Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
15090Sstevel@tonic-gate 	md_error_t	*ep = &status;
15100Sstevel@tonic-gate 	sdssc_boolean_e	cluster_take = SDSSC_False;
15110Sstevel@tonic-gate 	sdssc_version_t	vers;
15120Sstevel@tonic-gate 	rval_e		rval;
1513*1945Sjeanm 	int		set_take_rval;
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	/* reset and parse args */
15160Sstevel@tonic-gate 	optind = 1;
15170Sstevel@tonic-gate 	opterr = 1;
15181320Srd117015 	while ((c = getopt(argc, argv, "C:fs:tu:y")) != -1) {
15190Sstevel@tonic-gate 		switch (c) {
15200Sstevel@tonic-gate 		case 'C':
15210Sstevel@tonic-gate 			cluster_take = SDSSC_True;
15220Sstevel@tonic-gate 			break;
15230Sstevel@tonic-gate 		case 'f':
15240Sstevel@tonic-gate 			flags |= TAKE_FORCE;
15250Sstevel@tonic-gate 			break;
15260Sstevel@tonic-gate 		case 's':
15270Sstevel@tonic-gate 			sname = optarg;
15280Sstevel@tonic-gate 			break;
15290Sstevel@tonic-gate 		case 't':
15300Sstevel@tonic-gate 			break;
15310Sstevel@tonic-gate 		case 'u':
15320Sstevel@tonic-gate 			usetag = atoi(optarg);
15330Sstevel@tonic-gate 			flags |= TAKE_USETAG;
15340Sstevel@tonic-gate 			break;
15350Sstevel@tonic-gate 		case 'y':
15360Sstevel@tonic-gate 			flags |= TAKE_USEIT;
15370Sstevel@tonic-gate 			break;
15380Sstevel@tonic-gate 		default:
15390Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
15400Sstevel@tonic-gate 		}
15410Sstevel@tonic-gate 	}
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	mhiargs = defmhiargs;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	argc -= optind;
15460Sstevel@tonic-gate 	argv += optind;
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	if (argc > 1)
15490Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	/*
15520Sstevel@tonic-gate 	 * If we have a list of timeout value overrides, handle it here
15530Sstevel@tonic-gate 	 */
15540Sstevel@tonic-gate 	while (argv[0] != NULL && *argv[0] != '\0') {
15550Sstevel@tonic-gate 		/*
15560Sstevel@tonic-gate 		 * The use of the nullopts[] "token list" here is to make
15570Sstevel@tonic-gate 		 * getsubopts() simply parse a comma separated list
15580Sstevel@tonic-gate 		 * returning either "" or the contents of the field, the
15590Sstevel@tonic-gate 		 * end condition is exaustion of the initial string, which
15600Sstevel@tonic-gate 		 * is modified in the process.
15610Sstevel@tonic-gate 		 */
15620Sstevel@tonic-gate 		(void) getsubopt(&argv[0], nullopts, &cp);
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 		c = 0;			/* re-use c as temp value of timeout */
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 		if (*cp != '-')		/* '-' uses default */
15670Sstevel@tonic-gate 			c = atoi(cp);
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 		if (c < 0) {
15700Sstevel@tonic-gate 			usage(sp, gettext(
15710Sstevel@tonic-gate 			    "time out values must be > 0"));
15720Sstevel@tonic-gate 		}
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 		if (++pos > 3) {
15750Sstevel@tonic-gate 			usage(sp, gettext(
15760Sstevel@tonic-gate 			    "too many timeout values specified."));
15770Sstevel@tonic-gate 		}
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 		if (c == 0)		/* 0 or "" field uses default */
15800Sstevel@tonic-gate 			continue;
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 		/*
15830Sstevel@tonic-gate 		 * Assign temp value to appropriate structure member based on
15840Sstevel@tonic-gate 		 * its position in the comma separated list.
15850Sstevel@tonic-gate 		 */
15860Sstevel@tonic-gate 		switch (pos) {
15870Sstevel@tonic-gate 		    case 0:
15880Sstevel@tonic-gate 			mhiargs.mh_ff = c;
15890Sstevel@tonic-gate 			break;
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate 		    case 1:
15920Sstevel@tonic-gate 			mhiargs.mh_tk.reinstate_resv_delay = c;
15930Sstevel@tonic-gate 			break;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 		    case 2:
15960Sstevel@tonic-gate 			mhiargs.mh_tk.min_ownership_delay = c;
15970Sstevel@tonic-gate 			break;
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 		    case 3:
16000Sstevel@tonic-gate 			mhiargs.mh_tk.max_ownership_delay = c;
16010Sstevel@tonic-gate 			break;
16020Sstevel@tonic-gate 		}
16030Sstevel@tonic-gate 	}
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	memset(&vers, 0, sizeof (vers));
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	if ((sdssc_version(&vers) == SDSSC_OKAY) &&
16080Sstevel@tonic-gate 	    (vers.major == 3) &&
16090Sstevel@tonic-gate 	    (cluster_take == SDSSC_False)) {
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 		/*
16120Sstevel@tonic-gate 		 * If the take is beging done by the user via the CLI we need
16130Sstevel@tonic-gate 		 * to notify the DCS to make this current node the primary.
16140Sstevel@tonic-gate 		 * The SC3.0 reservation code will in turn exec metaset with
16150Sstevel@tonic-gate 		 * the -C take arg to complete this operation.
16160Sstevel@tonic-gate 		 */
16170Sstevel@tonic-gate 		if ((rval = sdssc_notify_service(sname, Make_Primary)) ==
16180Sstevel@tonic-gate 		    SDSSC_ERROR) {
16190Sstevel@tonic-gate 			printf(gettext(
16200Sstevel@tonic-gate 			    "metaset: failed to notify DCS of take\n"));
16210Sstevel@tonic-gate 		}
16220Sstevel@tonic-gate 		md_exit(NULL, rval == SDSSC_ERROR);
16230Sstevel@tonic-gate 	}
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
16260Sstevel@tonic-gate 		mde_perror(ep, "");
16270Sstevel@tonic-gate 		md_exit(sp, 1);
16280Sstevel@tonic-gate 	}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	if ((vers.major == 3) && (meta_check_ownership(sp, ep) == 0)) {
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 		/*
16330Sstevel@tonic-gate 		 * If we're running in a cluster environment and this
16340Sstevel@tonic-gate 		 * node already owns the set. Don't bother trying to
16350Sstevel@tonic-gate 		 * take the set again. There's one case where an adminstrator
16360Sstevel@tonic-gate 		 * is adding disks to a set for the first time. metaset
16370Sstevel@tonic-gate 		 * will take the ownership of the set at that point. During
16380Sstevel@tonic-gate 		 * that add operation SC3.0 notices activity on the device
16390Sstevel@tonic-gate 		 * and also tries to perform a take operation. The SC3.0 take
16400Sstevel@tonic-gate 		 * will fail because the adminstrative add has the set locked
16410Sstevel@tonic-gate 		 */
16420Sstevel@tonic-gate 		md_exit(sp, 0);
16430Sstevel@tonic-gate 	}
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
16461320Srd117015 		mde_perror(ep, "");
16471320Srd117015 		md_exit(sp, 10);	/* special errcode */
16480Sstevel@tonic-gate 	}
16490Sstevel@tonic-gate 
1650*1945Sjeanm 	/*
1651*1945Sjeanm 	 * If a 2 is returned from meta_set_take, this take was able to resolve
1652*1945Sjeanm 	 * an unresolved replicated disk (i.e. a disk is now available that
1653*1945Sjeanm 	 * had been missing during the import of the replicated diskset).
1654*1945Sjeanm 	 * Need to release the diskset and re-take in order to have
1655*1945Sjeanm 	 * the subdrivers re-snarf using the newly resolved (or newly mapped)
1656*1945Sjeanm 	 * devids.  This also allows the namespace to be updated with the
1657*1945Sjeanm 	 * correct major names in the case where the disk being replicated
1658*1945Sjeanm 	 * was handled by a different driver than the replicated disk.
1659*1945Sjeanm 	 */
1660*1945Sjeanm 	set_take_rval = meta_set_take(sp, &mhiargs, flags, usetag, &status);
1661*1945Sjeanm 	if (set_take_rval == 2) {
1662*1945Sjeanm 		if (meta_set_release(sp, &status)) {
1663*1945Sjeanm 			mde_perror(&status,
1664*1945Sjeanm 			    "Need to release and take set to resolve names.");
1665*1945Sjeanm 			md_exit(sp, 1);
1666*1945Sjeanm 		}
1667*1945Sjeanm 		metaflushdrivenames();
1668*1945Sjeanm 		metaflushsetname(sp);
1669*1945Sjeanm 		set_take_rval = meta_set_take(sp, &mhiargs,
1670*1945Sjeanm 		    (flags | TAKE_RETAKE), usetag, &status);
1671*1945Sjeanm 	}
1672*1945Sjeanm 
1673*1945Sjeanm 	if (set_take_rval == -1) {
16740Sstevel@tonic-gate 		mde_perror(&status, "");
16750Sstevel@tonic-gate 		if (mdismddberror(&status, MDE_DB_TAGDATA))
16760Sstevel@tonic-gate 			md_exit(sp, 2);
16770Sstevel@tonic-gate 		if (mdismddberror(&status, MDE_DB_ACCOK))
16780Sstevel@tonic-gate 			md_exit(sp, 3);
16790Sstevel@tonic-gate 		if (mdismddberror(&status, MDE_DB_STALE))
16800Sstevel@tonic-gate 			md_exit(sp, 66);
16810Sstevel@tonic-gate 		md_exit(sp, 1);
16820Sstevel@tonic-gate 	}
16830Sstevel@tonic-gate 	md_exit(sp, 0);
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate /*
16870Sstevel@tonic-gate  * Joins a node to a specific set or to all multinode disksets known
16880Sstevel@tonic-gate  * by this node.  If set is specified then caller should have verified
16890Sstevel@tonic-gate  * that the set is a multinode diskset.
16900Sstevel@tonic-gate  *
16910Sstevel@tonic-gate  * If an error occurs, metaset exits with a 1.
16920Sstevel@tonic-gate  * If there is no error, metaset exits with a 0.
16930Sstevel@tonic-gate  */
16940Sstevel@tonic-gate static void
16950Sstevel@tonic-gate parse_joinset(int argc, char **argv)
16960Sstevel@tonic-gate {
16970Sstevel@tonic-gate 	int		c;
16980Sstevel@tonic-gate 	mdsetname_t	*sp = NULL, *local_sp = NULL;
16990Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
17000Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
17010Sstevel@tonic-gate 	md_error_t	*ep = &status;
17020Sstevel@tonic-gate 	md_set_desc	*sd;
17030Sstevel@tonic-gate 	char		buf[BUFSIZ];
17040Sstevel@tonic-gate 	char		*p = buf;
17050Sstevel@tonic-gate 	set_t		max_sets, setno;
17060Sstevel@tonic-gate 	int		err, cumm_err = 0;
17070Sstevel@tonic-gate 	size_t		bufsz;
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	bufsz = sizeof (buf);
17100Sstevel@tonic-gate 	/* reset and parse args */
17110Sstevel@tonic-gate 	optind = 1;
17120Sstevel@tonic-gate 	opterr = 1;
17130Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Ms:j")) != -1) {
17140Sstevel@tonic-gate 		switch (c) {
17150Sstevel@tonic-gate 		case 'M':
17160Sstevel@tonic-gate 			break;
17170Sstevel@tonic-gate 		case 'j':
17180Sstevel@tonic-gate 			break;
17190Sstevel@tonic-gate 		case 's':
17200Sstevel@tonic-gate 			sname = optarg;
17210Sstevel@tonic-gate 			break;
17220Sstevel@tonic-gate 		default:
17230Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
17240Sstevel@tonic-gate 		}
17250Sstevel@tonic-gate 	}
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	argc -= optind;
17280Sstevel@tonic-gate 	argv += optind;
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	if (argc > 1)
17310Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 	/*
17340Sstevel@tonic-gate 	 * If no setname option was used, then join all disksets
17350Sstevel@tonic-gate 	 * that this node knows about.   Attempt to join all
17360Sstevel@tonic-gate 	 * disksets that this node knows about.
17370Sstevel@tonic-gate 	 *
17380Sstevel@tonic-gate 	 * Additional text is added to the error messages during
17390Sstevel@tonic-gate 	 * this section of code in order to help the user understand
17400Sstevel@tonic-gate 	 * why the 'join of all sets' failed and which set caused
17410Sstevel@tonic-gate 	 * the failure.
17420Sstevel@tonic-gate 	 */
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	/*
17450Sstevel@tonic-gate 	 * Hold local set lock throughout this call to keep
17460Sstevel@tonic-gate 	 * other actions from interfering (such as creating a new
17470Sstevel@tonic-gate 	 * set, etc.).
17480Sstevel@tonic-gate 	 */
17490Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
17500Sstevel@tonic-gate 		mde_perror(ep, "");
17510Sstevel@tonic-gate 		md_exit(sp, 1);
17520Sstevel@tonic-gate 	}
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
17550Sstevel@tonic-gate 		mde_perror(ep, "");
17560Sstevel@tonic-gate 		md_exit(local_sp, 1);
17570Sstevel@tonic-gate 	}
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) == 0) {
17600Sstevel@tonic-gate 		/*
17610Sstevel@tonic-gate 		 * If no set name is given, then walk through all sets
17620Sstevel@tonic-gate 		 * on this node which could include:
17630Sstevel@tonic-gate 		 * 	- MN disksets
17640Sstevel@tonic-gate 		 *	- traditional disksets
17650Sstevel@tonic-gate 		 *	- non-existent disksets
17660Sstevel@tonic-gate 		 * Attempt to join the MN disksets.
17670Sstevel@tonic-gate 		 * If the join of one set fails, print out an error message
17680Sstevel@tonic-gate 		 * about that set and continue the walk.
17690Sstevel@tonic-gate 		 */
17700Sstevel@tonic-gate 		if ((max_sets = get_max_sets(ep)) == 0) {
17710Sstevel@tonic-gate 			mde_perror(ep, "");
17720Sstevel@tonic-gate 			md_exit(local_sp, 1);
17730Sstevel@tonic-gate 		}
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 		/* Start walking through all possible disksets */
17760Sstevel@tonic-gate 		for (setno = 1; setno < max_sets; setno++) {
17770Sstevel@tonic-gate 			if ((sp = metasetnosetname(setno, ep)) == NULL) {
17780Sstevel@tonic-gate 				if (mdiserror(ep, MDE_NO_SET)) {
17790Sstevel@tonic-gate 					/* No set for this setno - continue */
17800Sstevel@tonic-gate 					mdclrerror(ep);
17810Sstevel@tonic-gate 					continue;
17820Sstevel@tonic-gate 				} else {
17830Sstevel@tonic-gate 					(void) sprintf(p, gettext(
17840Sstevel@tonic-gate 					"Unable to get set %d information"),
17850Sstevel@tonic-gate 					    setno);
17860Sstevel@tonic-gate 					mde_perror(ep, p);
17870Sstevel@tonic-gate 					cumm_err = 1;
17880Sstevel@tonic-gate 					mdclrerror(ep);
17890Sstevel@tonic-gate 					continue;
17900Sstevel@tonic-gate 				}
17910Sstevel@tonic-gate 			}
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 			/* If setname is there, set desc should exist. */
17940Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
17950Sstevel@tonic-gate 				(void) snprintf(p, bufsz, gettext(
17960Sstevel@tonic-gate 				    "Unable to get set %s desc information"),
17970Sstevel@tonic-gate 				    sp->setname);
17980Sstevel@tonic-gate 				mde_perror(ep, p);
17990Sstevel@tonic-gate 				cumm_err = 1;
18000Sstevel@tonic-gate 				mdclrerror(ep);
18010Sstevel@tonic-gate 				continue;
18020Sstevel@tonic-gate 			}
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 			/* Only check MN disksets */
18050Sstevel@tonic-gate 			if (!MD_MNSET_DESC(sd)) {
18060Sstevel@tonic-gate 				continue;
18070Sstevel@tonic-gate 			}
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 			/*
18100Sstevel@tonic-gate 			 * Return value of 0 is success.
18110Sstevel@tonic-gate 			 * Return value of -1 means a failure.
18120Sstevel@tonic-gate 			 * Return value of -2 means set could not be
18130Sstevel@tonic-gate 			 * joined, but shouldn't cause an error.
18140Sstevel@tonic-gate 			 * Reasons would be:
18150Sstevel@tonic-gate 			 * 	- no drives in set
18160Sstevel@tonic-gate 			 * 	- node already joined to set
18170Sstevel@tonic-gate 			 * Return value of -3 means joined stale set.
18180Sstevel@tonic-gate 			 * Can't check for all reasons here
18190Sstevel@tonic-gate 			 * since set isn't locked yet across all
18200Sstevel@tonic-gate 			 * nodes in the cluster.  The call
18210Sstevel@tonic-gate 			 * to libmeta routine, meta_set_join, will
18220Sstevel@tonic-gate 			 * lock across the cluster and perform
18230Sstevel@tonic-gate 			 * the checks.
18240Sstevel@tonic-gate 			 */
18250Sstevel@tonic-gate 			if ((err = meta_set_join(sp, ep)) == -1) {
18260Sstevel@tonic-gate 				/* Print error of diskset join failure */
18270Sstevel@tonic-gate 				(void) snprintf(p, bufsz,
18280Sstevel@tonic-gate 				    gettext("Join to diskset %s failed"),
18290Sstevel@tonic-gate 				    sp->setname);
18300Sstevel@tonic-gate 				mde_perror(ep, p);
18310Sstevel@tonic-gate 				cumm_err = 1;
18320Sstevel@tonic-gate 				mdclrerror(ep);
18330Sstevel@tonic-gate 				continue;
18340Sstevel@tonic-gate 			}
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 			if (err == -3) {
18370Sstevel@tonic-gate 				/* Print error of diskset join failure */
18380Sstevel@tonic-gate 				(void) snprintf(p, bufsz,
18390Sstevel@tonic-gate 				    gettext("Joined to stale diskset %s"),
18400Sstevel@tonic-gate 				    sp->setname);
18410Sstevel@tonic-gate 				mde_perror(ep, p);
18420Sstevel@tonic-gate 				mdclrerror(ep);
18430Sstevel@tonic-gate 			}
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 			mdclrerror(ep);
18460Sstevel@tonic-gate 		}
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 		md_exit(local_sp, cumm_err);
18490Sstevel@tonic-gate 	}
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	/*
18520Sstevel@tonic-gate 	 * Code for a specific set is much simpler.
18530Sstevel@tonic-gate 	 * Error messages don't need extra text since specific setname
18540Sstevel@tonic-gate 	 * was used.
18550Sstevel@tonic-gate 	 * Don't need to lock the local set, just the specific set given.
18560Sstevel@tonic-gate 	 */
18570Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
18580Sstevel@tonic-gate 		mde_perror(ep, "");
18590Sstevel@tonic-gate 		md_exit(local_sp, 1);
18600Sstevel@tonic-gate 	}
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	/*
18630Sstevel@tonic-gate 	 * Fail command if meta_set_join returns -1.
18640Sstevel@tonic-gate 	 *
18650Sstevel@tonic-gate 	 * Return of 0 means that node joined set.
18660Sstevel@tonic-gate 	 *
18670Sstevel@tonic-gate 	 * Return of -2 means that node was unable to
18680Sstevel@tonic-gate 	 * join a set since that set had no drives
18690Sstevel@tonic-gate 	 * or that had already joined the set.  No
18700Sstevel@tonic-gate 	 * need to fail the command for these reasons.
18710Sstevel@tonic-gate 	 *
18720Sstevel@tonic-gate 	 * Return of -3 means that set is stale.
18730Sstevel@tonic-gate 	 * Return a value of 66 to historically match traditional disksets.
18740Sstevel@tonic-gate 	 */
18750Sstevel@tonic-gate 	if ((err = meta_set_join(sp, ep)) == -1) {
18760Sstevel@tonic-gate 		mde_perror(&status, "");
18770Sstevel@tonic-gate 		md_exit(local_sp, 1);
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	if (err == -3) {
18810Sstevel@tonic-gate 		/* Print error of diskset join failure */
18820Sstevel@tonic-gate 		(void) snprintf(p, bufsz,
18830Sstevel@tonic-gate 		    gettext("Joined to stale diskset %s"),
18840Sstevel@tonic-gate 		    sp->setname);
18850Sstevel@tonic-gate 		mde_perror(&status, "");
18860Sstevel@tonic-gate 		md_exit(local_sp, 66);
18870Sstevel@tonic-gate 	}
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	md_exit(local_sp, 0);
18900Sstevel@tonic-gate }
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate /*
18930Sstevel@tonic-gate  * Withdraws a node from a specific set or from all multinode disksets known
18940Sstevel@tonic-gate  * by this node.  If set is specified then caller should have verified
18950Sstevel@tonic-gate  * that the set is a multinode diskset.
18960Sstevel@tonic-gate  *
18970Sstevel@tonic-gate  * If an error occurs, metaset exits with a 1.
18980Sstevel@tonic-gate  * If there is no error, metaset exits with a 0.
18990Sstevel@tonic-gate  */
19000Sstevel@tonic-gate static void
19010Sstevel@tonic-gate parse_withdrawset(int argc, char **argv)
19020Sstevel@tonic-gate {
19030Sstevel@tonic-gate 	int		c;
19040Sstevel@tonic-gate 	mdsetname_t	*sp = NULL, *local_sp = NULL;
19050Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
19060Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
19070Sstevel@tonic-gate 	md_error_t	*ep = &status;
19080Sstevel@tonic-gate 	char		buf[BUFSIZ];
19090Sstevel@tonic-gate 	char		*p = buf;
19100Sstevel@tonic-gate 	md_set_desc	*sd;
19110Sstevel@tonic-gate 	set_t		max_sets, setno;
19120Sstevel@tonic-gate 	int		err, cumm_err = 0;
19130Sstevel@tonic-gate 	size_t		bufsz;
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	bufsz = sizeof (buf);
19160Sstevel@tonic-gate 	/* reset and parse args */
19170Sstevel@tonic-gate 	optind = 1;
19180Sstevel@tonic-gate 	opterr = 1;
19190Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Ms:w")) != -1) {
19200Sstevel@tonic-gate 		switch (c) {
19210Sstevel@tonic-gate 		case 'M':
19220Sstevel@tonic-gate 			break;
19230Sstevel@tonic-gate 		case 'w':
19240Sstevel@tonic-gate 			break;
19250Sstevel@tonic-gate 		case 's':
19260Sstevel@tonic-gate 			sname = optarg;
19270Sstevel@tonic-gate 			break;
19280Sstevel@tonic-gate 		default:
19290Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
19300Sstevel@tonic-gate 		}
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	argc -= optind;
19340Sstevel@tonic-gate 	argv += optind;
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	if (argc > 1)
19370Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	/*
19400Sstevel@tonic-gate 	 * If no setname option was used, then withdraw from all disksets
19410Sstevel@tonic-gate 	 * that this node knows about.
19420Sstevel@tonic-gate 	 *
19430Sstevel@tonic-gate 	 * Additional text is added to the error messages during
19440Sstevel@tonic-gate 	 * this section of code in order to help the user understand
19450Sstevel@tonic-gate 	 * why the 'withdraw from all sets' failed and which set caused
19460Sstevel@tonic-gate 	 * the failure.
19470Sstevel@tonic-gate 	 */
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 	/*
19500Sstevel@tonic-gate 	 * Hold local set lock throughout this call to keep
19510Sstevel@tonic-gate 	 * other actions from interfering (such as creating a new
19520Sstevel@tonic-gate 	 * set, etc.).
19530Sstevel@tonic-gate 	 */
19540Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
19550Sstevel@tonic-gate 		mde_perror(ep, "");
19560Sstevel@tonic-gate 		md_exit(sp, 1);
19570Sstevel@tonic-gate 	}
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
19600Sstevel@tonic-gate 		mde_perror(ep, "");
19610Sstevel@tonic-gate 		md_exit(local_sp, 1);
19620Sstevel@tonic-gate 	}
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) == 0) {
19650Sstevel@tonic-gate 		/*
19660Sstevel@tonic-gate 		 * If no set name is given, then walk through all sets
19670Sstevel@tonic-gate 		 * on this node which could include:
19680Sstevel@tonic-gate 		 * 	- MN disksets
19690Sstevel@tonic-gate 		 *	- traditional disksets
19700Sstevel@tonic-gate 		 *	- non-existent disksets
19710Sstevel@tonic-gate 		 * Attempt to withdraw from the MN disksets.
19720Sstevel@tonic-gate 		 * If the withdraw of one set fails, print out an error
19730Sstevel@tonic-gate 		 * message about that set and continue the walk.
19740Sstevel@tonic-gate 		 */
19750Sstevel@tonic-gate 		if ((max_sets = get_max_sets(ep)) == 0) {
19760Sstevel@tonic-gate 			mde_perror(ep, "");
19770Sstevel@tonic-gate 			md_exit(local_sp, 1);
19780Sstevel@tonic-gate 		}
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 		/* Start walking through all possible disksets */
19810Sstevel@tonic-gate 		for (setno = 1; setno < max_sets; setno++) {
19820Sstevel@tonic-gate 			if ((sp = metasetnosetname(setno, ep)) == NULL) {
19830Sstevel@tonic-gate 				if (mdiserror(ep, MDE_NO_SET)) {
19840Sstevel@tonic-gate 					/* No set for this setno - continue */
19850Sstevel@tonic-gate 					mdclrerror(ep);
19860Sstevel@tonic-gate 					continue;
19870Sstevel@tonic-gate 				} else {
19880Sstevel@tonic-gate 					(void) sprintf(p, gettext(
19890Sstevel@tonic-gate 					    "Unable to get set %d information"),
19900Sstevel@tonic-gate 					    setno);
19910Sstevel@tonic-gate 					mde_perror(ep, p);
19920Sstevel@tonic-gate 					cumm_err = 1;
19930Sstevel@tonic-gate 					mdclrerror(ep);
19940Sstevel@tonic-gate 					continue;
19950Sstevel@tonic-gate 				}
19960Sstevel@tonic-gate 			}
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 			/* If setname is there, set desc should exist. */
19990Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
20000Sstevel@tonic-gate 				(void) snprintf(p, bufsz, gettext(
20010Sstevel@tonic-gate 				    "Unable to get set %s desc information"),
20020Sstevel@tonic-gate 				    sp->setname);
20030Sstevel@tonic-gate 				mde_perror(ep, p);
20040Sstevel@tonic-gate 				cumm_err = 1;
20050Sstevel@tonic-gate 				mdclrerror(ep);
20060Sstevel@tonic-gate 				continue;
20070Sstevel@tonic-gate 			}
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 			/* Only check MN disksets */
20100Sstevel@tonic-gate 			if (!MD_MNSET_DESC(sd)) {
20110Sstevel@tonic-gate 				continue;
20120Sstevel@tonic-gate 			}
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 			/*
20150Sstevel@tonic-gate 			 * Return value of 0 is success.
20160Sstevel@tonic-gate 			 * Return value of -1 means a failure.
20170Sstevel@tonic-gate 			 * Return value of -2 means set could not be
20180Sstevel@tonic-gate 			 * withdrawn from, but this shouldn't cause
20190Sstevel@tonic-gate 			 * an error.  Reasons would be:
20200Sstevel@tonic-gate 			 * 	- no drives in set
20210Sstevel@tonic-gate 			 * 	- node already withdrawn from set
20220Sstevel@tonic-gate 			 * Can't check for all reasons here
20230Sstevel@tonic-gate 			 * since set isn't locked yet across all
20240Sstevel@tonic-gate 			 * nodes in the cluster.  The call
20250Sstevel@tonic-gate 			 * to libmeta routine, meta_set_withdraw, will
20260Sstevel@tonic-gate 			 * lock across the cluster and perform
20270Sstevel@tonic-gate 			 * the checks.
20280Sstevel@tonic-gate 			 */
20290Sstevel@tonic-gate 			if ((err = meta_set_withdraw(sp, ep)) == -1) {
20300Sstevel@tonic-gate 				/* Print error of diskset withdraw failure */
20310Sstevel@tonic-gate 				(void) snprintf(p, bufsz,
20320Sstevel@tonic-gate 				    gettext("Withdraw from diskset %s failed"),
20330Sstevel@tonic-gate 				    sp->setname);
20340Sstevel@tonic-gate 				mde_perror(ep, p);
20350Sstevel@tonic-gate 				mdclrerror(ep);
20360Sstevel@tonic-gate 				cumm_err = 1;
20370Sstevel@tonic-gate 				continue;
20380Sstevel@tonic-gate 			}
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 			if (err == -2) {
20410Sstevel@tonic-gate 				mdclrerror(ep);
20420Sstevel@tonic-gate 				continue;
20430Sstevel@tonic-gate 			}
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 			mdclrerror(ep);
20460Sstevel@tonic-gate 		}
20470Sstevel@tonic-gate 		md_exit(local_sp, cumm_err);
20480Sstevel@tonic-gate 	}
20490Sstevel@tonic-gate 
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	/*
20520Sstevel@tonic-gate 	 * Code for a specific set is much simpler.
20530Sstevel@tonic-gate 	 * Error messages don't need extra text since specific setname
20540Sstevel@tonic-gate 	 * was used.
20550Sstevel@tonic-gate 	 * Don't need to lock the local set, just the specific set given.
20560Sstevel@tonic-gate 	 */
20570Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
20580Sstevel@tonic-gate 		mde_perror(ep, "");
20590Sstevel@tonic-gate 		md_exit(local_sp, 1);
20600Sstevel@tonic-gate 	}
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	/*
20630Sstevel@tonic-gate 	 * Fail command if meta_set_withdraw returns -1.
20640Sstevel@tonic-gate 	 *
20650Sstevel@tonic-gate 	 * Return of 0 means that node withdrew from set.
20660Sstevel@tonic-gate 	 *
20670Sstevel@tonic-gate 	 * Return of -2 means that node was unable to
20680Sstevel@tonic-gate 	 * withdraw from a set since that set had no drives
20690Sstevel@tonic-gate 	 * or node was not joined to set.  No
20700Sstevel@tonic-gate 	 * need to fail the command for these reasons.
20710Sstevel@tonic-gate 	 */
20720Sstevel@tonic-gate 	if (meta_set_withdraw(sp, ep) == -1) {
20730Sstevel@tonic-gate 		mde_perror(&status, "");
20740Sstevel@tonic-gate 		md_exit(local_sp, 1);
20750Sstevel@tonic-gate 	}
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 	md_exit(local_sp, 0);
20780Sstevel@tonic-gate }
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate /*
20810Sstevel@tonic-gate  * Should never be called with sname of a Multinode diskset.
20820Sstevel@tonic-gate  */
20830Sstevel@tonic-gate static void
20840Sstevel@tonic-gate parse_cluster(int argc, char **argv)
20850Sstevel@tonic-gate {
20860Sstevel@tonic-gate 	int			c,
20870Sstevel@tonic-gate 				error,
20880Sstevel@tonic-gate 				new_argc,
20890Sstevel@tonic-gate 				x;
20900Sstevel@tonic-gate 	enum cluster_cmd	cmd = ccnotspecified;
20910Sstevel@tonic-gate 	char			*hostname = SDSSC_PROXY_PRIMARY,
20920Sstevel@tonic-gate 				*argument = NULL,
20930Sstevel@tonic-gate 				*sname = MD_LOCAL_NAME,
20940Sstevel@tonic-gate 				primary_node[SDSSC_NODE_NAME_LEN],
20950Sstevel@tonic-gate 				**new_argv = NULL,
20960Sstevel@tonic-gate 				**np = NULL;
20970Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
20980Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
20990Sstevel@tonic-gate 	md_error_t		*ep = &status;
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 	/* reset and parse args */
21020Sstevel@tonic-gate 	optind = 1;
21030Sstevel@tonic-gate 	opterr = 1;
21041320Srd117015 	while ((c = getopt(argc, argv, "C:s:h:ftu:yr")) != -1) {
21050Sstevel@tonic-gate 		switch (c) {
21060Sstevel@tonic-gate 		case 'C':
21070Sstevel@tonic-gate 			if (cmd != ccnotspecified) {
21080Sstevel@tonic-gate 				md_exit(sp, -1);
21090Sstevel@tonic-gate 			}
21100Sstevel@tonic-gate 			argument = optarg;
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 			if (strcmp(argument, "disksin") == 0) {
21130Sstevel@tonic-gate 				cmd = clusterdisksin;
21140Sstevel@tonic-gate 			} else if (strcmp(argument, "version") == 0) {
21150Sstevel@tonic-gate 				cmd = clusterversion;
21160Sstevel@tonic-gate 			} else if (strcmp(argument, "release") == 0) {
21170Sstevel@tonic-gate 				cmd = clusterrelease;
21180Sstevel@tonic-gate 			} else if (strcmp(argument, "take") == 0) {
21190Sstevel@tonic-gate 				cmd = clustertake;
21200Sstevel@tonic-gate 			} else if (strcmp(argument, "proxy") == 0) {
21210Sstevel@tonic-gate 				cmd = clusterproxy;
21220Sstevel@tonic-gate 			} else if (strcmp(argument, "purge") == 0) {
21230Sstevel@tonic-gate 				cmd = clusterpurge;
21240Sstevel@tonic-gate 			} else {
21250Sstevel@tonic-gate 				md_exit(sp, -1);
21260Sstevel@tonic-gate 			}
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 			break;
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 		case 'h':
21310Sstevel@tonic-gate 			hostname = optarg;
21320Sstevel@tonic-gate 			break;
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 		case 's':
21350Sstevel@tonic-gate 			sname = optarg;
21360Sstevel@tonic-gate 			break;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 		case 'f':
21390Sstevel@tonic-gate 		case 't':
21400Sstevel@tonic-gate 		case 'u':
21410Sstevel@tonic-gate 		case 'y':
21420Sstevel@tonic-gate 		case 'r':
21430Sstevel@tonic-gate 			break;
21440Sstevel@tonic-gate 
21450Sstevel@tonic-gate 		default:
21460Sstevel@tonic-gate 			md_exit(sp, -1);
21470Sstevel@tonic-gate 		}
21480Sstevel@tonic-gate 	}
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	/* Now call the appropriate command function. */
21510Sstevel@tonic-gate 	switch (cmd) {
21520Sstevel@tonic-gate 	case clusterversion:
21530Sstevel@tonic-gate 	    printclusterversion();
21540Sstevel@tonic-gate 	    break;
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 	case clusterdisksin:
21570Sstevel@tonic-gate 	    if (printdisksin(sname, ep)) {
21580Sstevel@tonic-gate 		md_exit(sp, -1);
21590Sstevel@tonic-gate 	    }
21600Sstevel@tonic-gate 	    break;
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	case clusterrelease:
21630Sstevel@tonic-gate 	    parse_releaseset(argc, argv);
21640Sstevel@tonic-gate 	    break;
21650Sstevel@tonic-gate 
21660Sstevel@tonic-gate 	case clustertake:
21670Sstevel@tonic-gate 	    parse_takeset(argc, argv);
21680Sstevel@tonic-gate 	    break;
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 	case clusterproxy:
21710Sstevel@tonic-gate 		/* Should never get here if sname is for MN diskset */
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 		if ((new_argv = calloc(argc, sizeof (char *))) == NULL) {
21740Sstevel@tonic-gate 			printf(gettext("Out of memory\n"));
21750Sstevel@tonic-gate 			md_exit(sp, 1);
21760Sstevel@tonic-gate 		}
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 		np = new_argv;
21790Sstevel@tonic-gate 		new_argc = 0;
21800Sstevel@tonic-gate 		memset(primary_node, '\0', SDSSC_NODE_NAME_LEN);
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate 		for (x = 0; x < argc; x++) {
21830Sstevel@tonic-gate 			if (strcmp(argv[x], "-C") == 0) {
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 				/*
21860Sstevel@tonic-gate 				 * Need to skip the '-C proxy' args so
21870Sstevel@tonic-gate 				 * just increase x by one and the work is
21880Sstevel@tonic-gate 				 * done.
21890Sstevel@tonic-gate 				 */
21900Sstevel@tonic-gate 				x++;
21910Sstevel@tonic-gate 			} else {
21920Sstevel@tonic-gate 				*np++ = strdup(argv[x]);
21930Sstevel@tonic-gate 				new_argc++;
21940Sstevel@tonic-gate 			}
21950Sstevel@tonic-gate 		}
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 		switch (sdssc_get_primary_host(sname, primary_node,
21980Sstevel@tonic-gate 		    SDSSC_NODE_NAME_LEN)) {
21990Sstevel@tonic-gate 		case SDSSC_ERROR:
22000Sstevel@tonic-gate 			md_exit(sp, 1);
22010Sstevel@tonic-gate 			break;
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 		case SDSSC_NO_SERVICE:
22040Sstevel@tonic-gate 			if (hostname != SDSSC_PROXY_PRIMARY) {
22050Sstevel@tonic-gate 				(void) strlcpy(primary_node, hostname,
22060Sstevel@tonic-gate 				    SDSSC_NODE_NAME_LEN);
22070Sstevel@tonic-gate 			}
22080Sstevel@tonic-gate 			break;
22090Sstevel@tonic-gate 		}
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 		if (sdssc_cmd_proxy(new_argc, new_argv,
22120Sstevel@tonic-gate 		    primary_node[0] == '\0' ? SDSSC_PROXY_PRIMARY :
22130Sstevel@tonic-gate 		    primary_node, &error) == SDSSC_PROXY_DONE) {
22140Sstevel@tonic-gate 			md_exit(sp, error);
22150Sstevel@tonic-gate 		} else {
22160Sstevel@tonic-gate 			printf(gettext(
22170Sstevel@tonic-gate 			    "Couldn't proxy command\n"));
22180Sstevel@tonic-gate 			md_exit(sp, 1);
22190Sstevel@tonic-gate 		}
22200Sstevel@tonic-gate 		break;
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	case clusterpurge:
22230Sstevel@tonic-gate 		parse_purge(argc, argv);
22240Sstevel@tonic-gate 		break;
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	default:
22270Sstevel@tonic-gate 	    break;
22280Sstevel@tonic-gate 	}
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	md_exit(sp, 0);
22310Sstevel@tonic-gate }
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate /*
22340Sstevel@tonic-gate  * parse args and do it
22350Sstevel@tonic-gate  */
22360Sstevel@tonic-gate int
22370Sstevel@tonic-gate main(int argc, char *argv[])
22380Sstevel@tonic-gate {
22390Sstevel@tonic-gate 	enum metaset_cmd	cmd = notspecified;
22400Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
22410Sstevel@tonic-gate 	md_error_t		*ep = &status;
22420Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
22430Sstevel@tonic-gate 	char			*hostname = SDSSC_PROXY_PRIMARY,
22440Sstevel@tonic-gate 				*sname = MD_LOCAL_NAME,
22450Sstevel@tonic-gate 				*auto_take_option = NULL,
22460Sstevel@tonic-gate 				primary_node[SDSSC_NODE_NAME_LEN];
22470Sstevel@tonic-gate 	int			error,
22480Sstevel@tonic-gate 				c,
22490Sstevel@tonic-gate 				auto_take = FALSE,
22500Sstevel@tonic-gate 				stat;
22510Sstevel@tonic-gate 	md_set_desc		*sd;
22520Sstevel@tonic-gate 	int			mflag = 0;
22530Sstevel@tonic-gate 	int			multi_node = 0;
22540Sstevel@tonic-gate 	rval_e			sdssc_res;
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	/*
22570Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
22580Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
22590Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
22600Sstevel@tonic-gate 	 * something.
22610Sstevel@tonic-gate 	 */
22620Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
22630Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
22640Sstevel@tonic-gate #endif
22650Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
22660Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 	sdssc_res = sdssc_bind_library();
22690Sstevel@tonic-gate 	if (sdssc_res == SDSSC_ERROR) {
22700Sstevel@tonic-gate 		printf(gettext(
22710Sstevel@tonic-gate 		    "%s: Interface error with libsds_sc.so\n"), argv[0]);
22720Sstevel@tonic-gate 		exit(1);
22730Sstevel@tonic-gate 	}
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 	/* initialize */
22760Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
22770Sstevel@tonic-gate 		mde_perror(ep, "");
22780Sstevel@tonic-gate 		md_exit(sp, 1);
22790Sstevel@tonic-gate 	}
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 	optind = 1;
22820Sstevel@tonic-gate 	opterr = 1;
22830Sstevel@tonic-gate 
22840Sstevel@tonic-gate 	/*
22850Sstevel@tonic-gate 	 * NOTE: The "C" option is strictly for cluster use. it is not
22860Sstevel@tonic-gate 	 * and should not be documented for the customer. - JST
22870Sstevel@tonic-gate 	 */
22881320Srd117015 	while ((c = getopt(argc, argv, "C:MaA:bdfh:jl:Lm:oPqrs:tu:wy?"))
22890Sstevel@tonic-gate 	    != -1) {
22900Sstevel@tonic-gate 		switch (c) {
22910Sstevel@tonic-gate 		case 'M':
22920Sstevel@tonic-gate 			mflag = 1;
22930Sstevel@tonic-gate 			break;
22940Sstevel@tonic-gate 		case 'A':
22950Sstevel@tonic-gate 			auto_take = TRUE;
22960Sstevel@tonic-gate 			if (optarg == NULL || !(strcmp(optarg, "enable") == 0 ||
22970Sstevel@tonic-gate 			    strcmp(optarg, "disable") == 0))
22980Sstevel@tonic-gate 				usage(sp, gettext(
22990Sstevel@tonic-gate 				    "-A: enable or disable must be specified"));
23000Sstevel@tonic-gate 			auto_take_option = optarg;
23010Sstevel@tonic-gate 			break;
23020Sstevel@tonic-gate 		case 'a':
23030Sstevel@tonic-gate 			if (cmd != notspecified) {
23040Sstevel@tonic-gate 				usage(sp, gettext(
23050Sstevel@tonic-gate 				    "conflicting options"));
23060Sstevel@tonic-gate 			}
23070Sstevel@tonic-gate 			cmd = add;
23080Sstevel@tonic-gate 			break;
23090Sstevel@tonic-gate 		case 'b':
23100Sstevel@tonic-gate 			if (cmd != notspecified) {
23110Sstevel@tonic-gate 				usage(sp, gettext(
23120Sstevel@tonic-gate 				    "conflicting options"));
23130Sstevel@tonic-gate 			}
23140Sstevel@tonic-gate 			cmd = balance;
23150Sstevel@tonic-gate 			break;
23160Sstevel@tonic-gate 		case 'd':
23170Sstevel@tonic-gate 			if (cmd != notspecified) {
23180Sstevel@tonic-gate 				usage(sp, gettext(
23190Sstevel@tonic-gate 				    "conflicting options"));
23200Sstevel@tonic-gate 			}
23210Sstevel@tonic-gate 			cmd = delete;
23220Sstevel@tonic-gate 			break;
23230Sstevel@tonic-gate 		case 'C':	/* cluster commands */
23240Sstevel@tonic-gate 			if (cmd != notspecified) {
23250Sstevel@tonic-gate 				md_exit(sp, -1);    /* conflicting options */
23260Sstevel@tonic-gate 			}
23270Sstevel@tonic-gate 			cmd = cluster;
23280Sstevel@tonic-gate 			break;
23290Sstevel@tonic-gate 		case 'f':
23300Sstevel@tonic-gate 			break;
23310Sstevel@tonic-gate 		case 'h':
23320Sstevel@tonic-gate 			hostname = optarg;
23330Sstevel@tonic-gate 			break;
23340Sstevel@tonic-gate 		case 'j':
23350Sstevel@tonic-gate 			if (cmd != notspecified) {
23360Sstevel@tonic-gate 				usage(sp, gettext(
23370Sstevel@tonic-gate 				    "conflicting options"));
23380Sstevel@tonic-gate 			}
23390Sstevel@tonic-gate 			cmd = join;
23400Sstevel@tonic-gate 			break;
23410Sstevel@tonic-gate 		case 'l':
23420Sstevel@tonic-gate 			break;
23430Sstevel@tonic-gate 		case 'L':
23440Sstevel@tonic-gate 			break;
23450Sstevel@tonic-gate 		case 'm':
23460Sstevel@tonic-gate 			break;
23470Sstevel@tonic-gate 		case 'o':
23480Sstevel@tonic-gate 			if (cmd != notspecified) {
23490Sstevel@tonic-gate 				usage(sp, gettext(
23500Sstevel@tonic-gate 				    "conflicting options"));
23510Sstevel@tonic-gate 			}
23520Sstevel@tonic-gate 			cmd = isowner;
23530Sstevel@tonic-gate 			break;
23540Sstevel@tonic-gate 		case 'P':
23550Sstevel@tonic-gate 			if (cmd != notspecified) {
23560Sstevel@tonic-gate 				usage(sp, gettext(
23570Sstevel@tonic-gate 				    "conflicting options"));
23580Sstevel@tonic-gate 			}
23590Sstevel@tonic-gate 			cmd = purge;
23600Sstevel@tonic-gate 			break;
23610Sstevel@tonic-gate 		case 'q':
23620Sstevel@tonic-gate 			if (cmd != notspecified) {
23630Sstevel@tonic-gate 				usage(sp, gettext(
23640Sstevel@tonic-gate 				    "conflicting options"));
23650Sstevel@tonic-gate 			}
23660Sstevel@tonic-gate 			cmd = query;
23670Sstevel@tonic-gate 			break;
23680Sstevel@tonic-gate 		case 'r':
23690Sstevel@tonic-gate 			if (cmd != notspecified) {
23700Sstevel@tonic-gate 				usage(sp, gettext(
23710Sstevel@tonic-gate 				    "conflicting options"));
23720Sstevel@tonic-gate 			}
23730Sstevel@tonic-gate 			cmd = release;
23740Sstevel@tonic-gate 			break;
23750Sstevel@tonic-gate 		case 's':
23760Sstevel@tonic-gate 			sname = optarg;
23770Sstevel@tonic-gate 			break;
23780Sstevel@tonic-gate 		case 't':
23790Sstevel@tonic-gate 			if (cmd != notspecified) {
23800Sstevel@tonic-gate 				usage(sp, gettext(
23810Sstevel@tonic-gate 				    "conflicting options"));
23820Sstevel@tonic-gate 			}
23830Sstevel@tonic-gate 			cmd = take;
23840Sstevel@tonic-gate 			break;
23850Sstevel@tonic-gate 		case 'u':
23860Sstevel@tonic-gate 			break;
23870Sstevel@tonic-gate 		case 'w':
23880Sstevel@tonic-gate 			if (cmd != notspecified) {
23890Sstevel@tonic-gate 				usage(sp, gettext(
23900Sstevel@tonic-gate 				    "conflicting options"));
23910Sstevel@tonic-gate 			}
23920Sstevel@tonic-gate 			cmd = withdraw;
23930Sstevel@tonic-gate 			break;
23940Sstevel@tonic-gate 		case 'y':
23950Sstevel@tonic-gate 			break;
23960Sstevel@tonic-gate 		case '?':
23970Sstevel@tonic-gate 			if (optopt == '?')
23980Sstevel@tonic-gate 				usage(sp, NULL);
23990Sstevel@tonic-gate 			/*FALLTHROUGH*/
24000Sstevel@tonic-gate 		default:
24010Sstevel@tonic-gate 			if (cmd == cluster) {    /* cluster is silent */
24020Sstevel@tonic-gate 				md_exit(sp, -1);
24030Sstevel@tonic-gate 			} else {
24040Sstevel@tonic-gate 				usage(sp, gettext(
24050Sstevel@tonic-gate 				    "unknown command"));
24060Sstevel@tonic-gate 			}
24070Sstevel@tonic-gate 		}
24080Sstevel@tonic-gate 	}
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 	/* check if suncluster is installed and -A enable specified */
24110Sstevel@tonic-gate 	if (auto_take && sdssc_res != SDSSC_NOT_BOUND &&
24120Sstevel@tonic-gate 	    strcmp(auto_take_option, "enable") == 0) {
24130Sstevel@tonic-gate 	    md_eprintf(gettext(
24140Sstevel@tonic-gate 		"cannot enable auto-take when SunCluster is installed\n"));
24150Sstevel@tonic-gate 	    md_exit(sp, 1);
24160Sstevel@tonic-gate 	}
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	/*
24190Sstevel@tonic-gate 	 * At this point we know that if the -A enable option is specified
24200Sstevel@tonic-gate 	 * for an auto-take diskset that SC is not installed on the machine, so
24210Sstevel@tonic-gate 	 * all of the sdssc calls will just be no-ops.
24220Sstevel@tonic-gate 	 */
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 	/* list sets */
24250Sstevel@tonic-gate 	if (cmd == notspecified && auto_take == FALSE) {
24260Sstevel@tonic-gate 		parse_printset(argc, argv);
24270Sstevel@tonic-gate 		/*NOTREACHED*/
24280Sstevel@tonic-gate 	}
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
24310Sstevel@tonic-gate 		mde_perror(ep, "");
24320Sstevel@tonic-gate 		md_exit(sp, 1);
24330Sstevel@tonic-gate 	}
24340Sstevel@tonic-gate 
24350Sstevel@tonic-gate 	/* snarf MDDB */
24360Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
24370Sstevel@tonic-gate 		mde_perror(ep, "");
24380Sstevel@tonic-gate 		md_exit(sp, 1);
24390Sstevel@tonic-gate 	}
24400Sstevel@tonic-gate 
24410Sstevel@tonic-gate 	/*
24420Sstevel@tonic-gate 	 * If sname is a diskset - check for multi_node.
24430Sstevel@tonic-gate 	 * It is possible for sname to not exist.
24440Sstevel@tonic-gate 	 */
24450Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME)) {
24460Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) != NULL) {
24470Sstevel@tonic-gate 			/* Set exists - check for MN diskset */
24480Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
24490Sstevel@tonic-gate 				mde_perror(ep, "");
24500Sstevel@tonic-gate 				md_exit(sp, 1);
24510Sstevel@tonic-gate 			}
24520Sstevel@tonic-gate 			if (MD_MNSET_DESC(sd)) {
24530Sstevel@tonic-gate 				/*
24540Sstevel@tonic-gate 				 * If a MN diskset always set multi_node
24550Sstevel@tonic-gate 				 * regardless of whether the -M option was
24560Sstevel@tonic-gate 				 * used or not (mflag).
24570Sstevel@tonic-gate 				 */
24580Sstevel@tonic-gate 				multi_node = 1;
24590Sstevel@tonic-gate 			} else {
24600Sstevel@tonic-gate 				/*
24610Sstevel@tonic-gate 				 * If a traditional diskset, mflag must
24620Sstevel@tonic-gate 				 * not be set.
24630Sstevel@tonic-gate 				 */
24640Sstevel@tonic-gate 				if (mflag) {
24650Sstevel@tonic-gate 					usage(sp, gettext(
24660Sstevel@tonic-gate 					    "-M option only allowed "
24670Sstevel@tonic-gate 					    "on multi-owner diskset"));
24680Sstevel@tonic-gate 				}
24690Sstevel@tonic-gate 			}
24700Sstevel@tonic-gate 		} else {
24710Sstevel@tonic-gate 			/*
24720Sstevel@tonic-gate 			 * Set name does not exist, set multi_node
24730Sstevel@tonic-gate 			 * based on -M option.
24740Sstevel@tonic-gate 			 */
24750Sstevel@tonic-gate 			if (mflag) {
24760Sstevel@tonic-gate 				multi_node = 1;
24770Sstevel@tonic-gate 			}
24780Sstevel@tonic-gate 		}
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	if (auto_take && multi_node) {
24820Sstevel@tonic-gate 		/* Can't mix multinode and auto-take on a diskset */
24830Sstevel@tonic-gate 		usage(sp,
24840Sstevel@tonic-gate 		    gettext("-A option not allowed on multi-owner diskset"));
24850Sstevel@tonic-gate 	}
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	/*
24880Sstevel@tonic-gate 	 * MN disksets don't use DCS clustering services, so
24890Sstevel@tonic-gate 	 * do not get primary_node for MN diskset since no command
24900Sstevel@tonic-gate 	 * proxying is done to Primary cluster node.  Do not proxy
24910Sstevel@tonic-gate 	 * MN diskset commands of join and withdraw when issued without
24920Sstevel@tonic-gate 	 * a valid setname.
24930Sstevel@tonic-gate 	 * For traditional disksets: proxy all commands except a take
24940Sstevel@tonic-gate 	 * and release.  Use first host listed as the host to send the
24950Sstevel@tonic-gate 	 * command to if there isn't already a primary
24960Sstevel@tonic-gate 	 */
24970Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) && (multi_node == 0) &&
24980Sstevel@tonic-gate 	    (cmd != take) && (cmd != release) &&
24990Sstevel@tonic-gate 	    (cmd != cluster) && (cmd != join) &&
25000Sstevel@tonic-gate 	    (cmd != withdraw) && (cmd != purge)) {
25010Sstevel@tonic-gate 		stat = sdssc_get_primary_host(sname, primary_node,
25020Sstevel@tonic-gate 		    SDSSC_NODE_NAME_LEN);
25030Sstevel@tonic-gate 		switch (stat) {
25040Sstevel@tonic-gate 			case SDSSC_ERROR:
25050Sstevel@tonic-gate 				return (0);
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 			case SDSSC_NO_SERVICE:
25080Sstevel@tonic-gate 				if (hostname != SDSSC_PROXY_PRIMARY) {
25090Sstevel@tonic-gate 					(void) strlcpy(primary_node, hostname,
25100Sstevel@tonic-gate 					    SDSSC_NODE_NAME_LEN);
25110Sstevel@tonic-gate 				} else {
25120Sstevel@tonic-gate 					memset(primary_node, '\0',
25130Sstevel@tonic-gate 					    SDSSC_NODE_NAME_LEN);
25140Sstevel@tonic-gate 				}
25150Sstevel@tonic-gate 				break;
25160Sstevel@tonic-gate 		}
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 		/*
25190Sstevel@tonic-gate 		 * We've got a complicated decision here regarding
25200Sstevel@tonic-gate 		 * the hostname. If we didn't get a primary host
25210Sstevel@tonic-gate 		 * and a host name wasn't supplied on the command line
25220Sstevel@tonic-gate 		 * then we need to revert to SDSSC_PROXY_PRIMARY. Otherwise
25230Sstevel@tonic-gate 		 * use what's been found.
25240Sstevel@tonic-gate 		 */
25250Sstevel@tonic-gate 		if (sdssc_cmd_proxy(argc, argv,
25260Sstevel@tonic-gate 		    primary_node[0] == '\0' ?
25270Sstevel@tonic-gate 			SDSSC_PROXY_PRIMARY : primary_node,
25280Sstevel@tonic-gate 		    &error) == SDSSC_PROXY_DONE) {
25290Sstevel@tonic-gate 			exit(error);
25300Sstevel@tonic-gate 		}
25310Sstevel@tonic-gate 	}
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	/* cluster-specific commands */
25340Sstevel@tonic-gate 	if (cmd == cluster) {
25350Sstevel@tonic-gate 		if (multi_node) {
25360Sstevel@tonic-gate 			/*
25370Sstevel@tonic-gate 			 * If a specific MN diskset is given, immediately
25380Sstevel@tonic-gate 			 * fail -C command.
25390Sstevel@tonic-gate 			 */
25400Sstevel@tonic-gate 			usage(sp, gettext(
25410Sstevel@tonic-gate 			    "-C option not allowed on multi-owner diskset"));
25420Sstevel@tonic-gate 		} else {
25430Sstevel@tonic-gate 			parse_cluster(argc, argv);
25440Sstevel@tonic-gate 			/*NOTREACHED*/
25450Sstevel@tonic-gate 		}
25460Sstevel@tonic-gate 	}
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	/* join MultiNode diskset */
25490Sstevel@tonic-gate 	if (cmd == join) {
25500Sstevel@tonic-gate 		/*
25510Sstevel@tonic-gate 		 * If diskset specified, verify that it exists
25520Sstevel@tonic-gate 		 * and is a multinode diskset.
25530Sstevel@tonic-gate 		 */
25540Sstevel@tonic-gate 		if (strcmp(sname, MD_LOCAL_NAME)) {
25550Sstevel@tonic-gate 			if ((sp = metasetname(sname, ep)) == NULL) {
25560Sstevel@tonic-gate 				mde_perror(ep, "");
25570Sstevel@tonic-gate 				md_exit(sp, 1);
25580Sstevel@tonic-gate 			}
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 			if (!multi_node) {
25610Sstevel@tonic-gate 				usage(sp, gettext(
25620Sstevel@tonic-gate 				    "-j option only allowed on "
25630Sstevel@tonic-gate 				    "multi-owner diskset"));
25640Sstevel@tonic-gate 			}
25650Sstevel@tonic-gate 		}
25660Sstevel@tonic-gate 		/*
25670Sstevel@tonic-gate 		 * Start mddoors daemon here.
25680Sstevel@tonic-gate 		 * mddoors itself takes care there will be only one
25690Sstevel@tonic-gate 		 * instance running, so starting it twice won't hurt
25700Sstevel@tonic-gate 		 */
25710Sstevel@tonic-gate 		pclose(popen("/usr/lib/lvm/mddoors", "w"));
25720Sstevel@tonic-gate 		parse_joinset(argc, argv);
25730Sstevel@tonic-gate 		/*NOTREACHED*/
25740Sstevel@tonic-gate 	}
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate 	/* withdraw from MultiNode diskset */
25770Sstevel@tonic-gate 	if (cmd == withdraw) {
25780Sstevel@tonic-gate 		/*
25790Sstevel@tonic-gate 		 * If diskset specified, verify that it exists
25800Sstevel@tonic-gate 		 * and is a multinode diskset.
25810Sstevel@tonic-gate 		 */
25820Sstevel@tonic-gate 		if (strcmp(sname, MD_LOCAL_NAME)) {
25830Sstevel@tonic-gate 			if ((sp = metasetname(sname, ep)) == NULL) {
25840Sstevel@tonic-gate 				mde_perror(ep, "");
25850Sstevel@tonic-gate 				md_exit(sp, 1);
25860Sstevel@tonic-gate 			}
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 			if (!multi_node) {
25890Sstevel@tonic-gate 				usage(sp, gettext(
25900Sstevel@tonic-gate 				    "-w option only allowed on "
25910Sstevel@tonic-gate 				    "multi-owner diskset"));
25920Sstevel@tonic-gate 			}
25930Sstevel@tonic-gate 		}
25940Sstevel@tonic-gate 		parse_withdrawset(argc, argv);
25950Sstevel@tonic-gate 		/*NOTREACHED*/
25960Sstevel@tonic-gate 	}
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 	/* must have set for everything else */
25990Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) == 0)
26000Sstevel@tonic-gate 		usage(sp, gettext("setname must be specified"));
26010Sstevel@tonic-gate 
26020Sstevel@tonic-gate 	/* add hosts or drives */
26030Sstevel@tonic-gate 	if (cmd == add) {
26040Sstevel@tonic-gate 		/*
26050Sstevel@tonic-gate 		 * In the multi node case start mddoors daemon.
26060Sstevel@tonic-gate 		 * mddoors itself takes care there will be
26070Sstevel@tonic-gate 		 * only one instance running, so starting it twice won't hurt
26080Sstevel@tonic-gate 		 */
26090Sstevel@tonic-gate 		if (multi_node) {
26100Sstevel@tonic-gate 			pclose(popen("/usr/lib/lvm/mddoors", "w"));
26110Sstevel@tonic-gate 		}
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 		parse_add(argc, argv);
26140Sstevel@tonic-gate 		/*NOTREACHED*/
26150Sstevel@tonic-gate 	}
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate 	/* re-balance the replicas */
26180Sstevel@tonic-gate 	if (cmd == balance) {
26190Sstevel@tonic-gate 		parse_balance(argc, argv);
26200Sstevel@tonic-gate 		/*NOTREACHED*/
26210Sstevel@tonic-gate 	}
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 	/* delete hosts or drives */
26240Sstevel@tonic-gate 	if (cmd == delete) {
26250Sstevel@tonic-gate 		parse_del(argc, argv);
26260Sstevel@tonic-gate 		/*NOTREACHED*/
26270Sstevel@tonic-gate 	}
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate 	/* check ownership */
26300Sstevel@tonic-gate 	if (cmd == isowner) {
26310Sstevel@tonic-gate 		parse_isowner(argc, argv);
26320Sstevel@tonic-gate 		/*NOTREACHED*/
26330Sstevel@tonic-gate 	}
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 	/* purge the diskset */
26360Sstevel@tonic-gate 	if (cmd == purge) {
26370Sstevel@tonic-gate 		parse_purge(argc, argv);
26380Sstevel@tonic-gate 		/*NOTREACHED*/
26390Sstevel@tonic-gate 	}
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	/* query for data marks */
26420Sstevel@tonic-gate 	if (cmd == query) {
26430Sstevel@tonic-gate 		parse_query(argc, argv);
26440Sstevel@tonic-gate 		/*NOTREACHED*/
26450Sstevel@tonic-gate 	}
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	/* release ownership */
26480Sstevel@tonic-gate 	if (cmd == release) {
26490Sstevel@tonic-gate 		if (multi_node) {
26500Sstevel@tonic-gate 			/* Can't release multinode diskset */
26510Sstevel@tonic-gate 			usage(sp, gettext(
26520Sstevel@tonic-gate 			    "-r option not allowed on multi-owner diskset"));
26530Sstevel@tonic-gate 		} else {
26540Sstevel@tonic-gate 			parse_releaseset(argc, argv);
26550Sstevel@tonic-gate 			/*NOTREACHED*/
26560Sstevel@tonic-gate 		}
26570Sstevel@tonic-gate 	}
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 	/* take ownership */
26600Sstevel@tonic-gate 	if (cmd == take) {
26610Sstevel@tonic-gate 		if (multi_node) {
26620Sstevel@tonic-gate 			/* Can't take multinode diskset */
26630Sstevel@tonic-gate 			usage(sp, gettext(
26640Sstevel@tonic-gate 			    "-t option not allowed on multi-owner diskset"));
26650Sstevel@tonic-gate 		} else {
26660Sstevel@tonic-gate 			parse_takeset(argc, argv);
26670Sstevel@tonic-gate 			/*NOTREACHED*/
26680Sstevel@tonic-gate 		}
26690Sstevel@tonic-gate 	}
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	/* take ownership of auto-take sets */
26720Sstevel@tonic-gate 	if (auto_take) {
26730Sstevel@tonic-gate 		parse_autotake(argc, argv);
26740Sstevel@tonic-gate 		/*NOTREACHED*/
26750Sstevel@tonic-gate 	}
26760Sstevel@tonic-gate 
26770Sstevel@tonic-gate 	/*NOTREACHED*/
26780Sstevel@tonic-gate 	return (0);
26790Sstevel@tonic-gate }
2680