1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Metadevice diskset utility.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <meta.h>
34*0Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
35*0Sstevel@tonic-gate #include <sdssc.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate enum metaset_cmd {
38*0Sstevel@tonic-gate 	notspecified,
39*0Sstevel@tonic-gate 	add,
40*0Sstevel@tonic-gate 	balance,
41*0Sstevel@tonic-gate 	delete,
42*0Sstevel@tonic-gate 	cluster,
43*0Sstevel@tonic-gate 	isowner,
44*0Sstevel@tonic-gate 	purge,
45*0Sstevel@tonic-gate 	query,
46*0Sstevel@tonic-gate 	release,
47*0Sstevel@tonic-gate 	take,
48*0Sstevel@tonic-gate 	join,			/* Join a multinode diskset */
49*0Sstevel@tonic-gate 	withdraw		/* Withdraw from a multinode diskset */
50*0Sstevel@tonic-gate };
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate enum cluster_cmd {
53*0Sstevel@tonic-gate 	ccnotspecified,
54*0Sstevel@tonic-gate 	clusterversion,		/* Return the version of the cluster I/F */
55*0Sstevel@tonic-gate 	clusterdisksin,		/* List disks in a given diskset */
56*0Sstevel@tonic-gate 	clustertake,		/* back door for Cluster take */
57*0Sstevel@tonic-gate 	clusterrelease,		/* ditto */
58*0Sstevel@tonic-gate 	clusterpurge,		/* back door for Cluster purge */
59*0Sstevel@tonic-gate 	clusterproxy		/* proxy the args after '--' to primary */
60*0Sstevel@tonic-gate };
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate static void
63*0Sstevel@tonic-gate usage(
64*0Sstevel@tonic-gate 	mdsetname_t	*sp,
65*0Sstevel@tonic-gate 	char		*string)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	if ((string != NULL) && (*string != '\0'))
68*0Sstevel@tonic-gate 		md_eprintf("%s\n", string);
69*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
70*0Sstevel@tonic-gate "usage:	%s -s setname -a [-A enable | disable] -h hostname ...\n"
71*0Sstevel@tonic-gate "	%s -s setname -a [-M] -h hostname ...\n"
72*0Sstevel@tonic-gate "	%s -s setname -a [-M] [-l length] [-L] drivename ...\n"
73*0Sstevel@tonic-gate "	%s -s setname -d [-M] -h hostname ...\n"
74*0Sstevel@tonic-gate "	%s -s setname -d [-M] -f -h all-hostnames\n"
75*0Sstevel@tonic-gate "	%s -s setname -d [-M] [-f] drivename ...\n"
76*0Sstevel@tonic-gate "	%s -s setname -d [-M] [-f] hostname ...\n"
77*0Sstevel@tonic-gate "	%s -s setname -A enable | disable\n"
78*0Sstevel@tonic-gate "	%s -s setname -t [-f]\n"
79*0Sstevel@tonic-gate "	%s -s setname -r\n"
80*0Sstevel@tonic-gate "	%s [-s setname] -j [-M]\n"
81*0Sstevel@tonic-gate "	%s [-s setname] -w [-M]\n"
82*0Sstevel@tonic-gate "	%s -s setname -P [-M]\n"
83*0Sstevel@tonic-gate "	%s -s setname -b [-M]\n"
84*0Sstevel@tonic-gate "	%s -s setname -o [-M] [-h hostname]\n"
85*0Sstevel@tonic-gate "	%s [-s setname]\n"
86*0Sstevel@tonic-gate "\n"
87*0Sstevel@tonic-gate "		hostname = contents of /etc/nodename\n"
88*0Sstevel@tonic-gate "		drivename = cNtNdN no slice\n"
89*0Sstevel@tonic-gate "		[-M] for multi-owner set is optional except on set creation\n"),
90*0Sstevel@tonic-gate 	myname, myname, myname, myname, myname, myname, myname, myname,
91*0Sstevel@tonic-gate 	myname, myname, myname, myname, myname, myname, myname, myname);
92*0Sstevel@tonic-gate 	md_exit(sp, (string == NULL) ? 0 : 1);
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * The svm.sync rc script relies heavily on the metaset output.
97*0Sstevel@tonic-gate  * Any changes to the metaset output MUST verify that the rc script
98*0Sstevel@tonic-gate  * does not break. Not doing so may potentially leave the system
99*0Sstevel@tonic-gate  * unusable. You have been WARNED.
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate static int
102*0Sstevel@tonic-gate printset(mdsetname_t *sp, md_error_t *ep)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	int			i, j;
105*0Sstevel@tonic-gate 	md_set_desc		*sd;
106*0Sstevel@tonic-gate 	md_drive_desc		*dd, *p;
107*0Sstevel@tonic-gate 	int			max_meds;
108*0Sstevel@tonic-gate 	md_mnnode_desc		*nd;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL)
111*0Sstevel@tonic-gate 		return (-1);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	/*
114*0Sstevel@tonic-gate 	 * Only get set owner information for traditional diskset.
115*0Sstevel@tonic-gate 	 * This set owner information is stored in the node records
116*0Sstevel@tonic-gate 	 * for a MN diskset.
117*0Sstevel@tonic-gate 	 */
118*0Sstevel@tonic-gate 	if (!(MD_MNSET_DESC(sd))) {
119*0Sstevel@tonic-gate 		if (metaget_setownership(sp, ep) == -1)
120*0Sstevel@tonic-gate 			return (-1);
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
124*0Sstevel@tonic-gate 	    ep)) == NULL) && !mdisok(ep))
125*0Sstevel@tonic-gate 		return (-1);
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
128*0Sstevel@tonic-gate 		(void) printf(gettext(
129*0Sstevel@tonic-gate 		"\nMulti-owner Set name = %s, Set number = %d, Master = %s\n"),
130*0Sstevel@tonic-gate 		    sp->setname, sp->setno, sd->sd_mn_master_nodenm);
131*0Sstevel@tonic-gate 		if ((sd->sd_mn_master_nodeid == MD_MN_INVALID_NID) &&
132*0Sstevel@tonic-gate 		    (dd != NULL)) {
133*0Sstevel@tonic-gate 			(void) printf(gettext(
134*0Sstevel@tonic-gate 				"Master and owner information unavailable "
135*0Sstevel@tonic-gate 				"until joined (metaset -j)\n"));
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 	} else {
138*0Sstevel@tonic-gate 		(void) printf(gettext(
139*0Sstevel@tonic-gate 		    "\nSet name = %s, Set number = %d\n"),
140*0Sstevel@tonic-gate 		    sp->setname, sp->setno);
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
144*0Sstevel@tonic-gate 		(void) printf(gettext("\n%-19.19s %-14.14s %-6.6s\n"),
145*0Sstevel@tonic-gate 			gettext("Host"), gettext("Owner"), gettext("Member"));
146*0Sstevel@tonic-gate 		nd = sd->sd_nodelist;
147*0Sstevel@tonic-gate 		while (nd) {
148*0Sstevel@tonic-gate 			/*
149*0Sstevel@tonic-gate 			 * Don't print nodes that aren't ok since they may be
150*0Sstevel@tonic-gate 			 * removed from config during a reconfig cycle.  If a
151*0Sstevel@tonic-gate 			 * node was being added to a diskset and the entire
152*0Sstevel@tonic-gate 			 * cluster went down but the node being added was unable
153*0Sstevel@tonic-gate 			 * to reboot, there's no way to know if that node had
154*0Sstevel@tonic-gate 			 * its own node record set to OK or not.  So, node
155*0Sstevel@tonic-gate 			 * record is left in ADD state during reconfig cycle.
156*0Sstevel@tonic-gate 			 * When that node reboots and returns to the cluster,
157*0Sstevel@tonic-gate 			 * the reconfig cycle will either remove the node
158*0Sstevel@tonic-gate 			 * record (if not marked OK on that node) or will mark
159*0Sstevel@tonic-gate 			 * it OK on all nodes.
160*0Sstevel@tonic-gate 			 * It is very important to only remove a node record
161*0Sstevel@tonic-gate 			 * from the other nodes when that node record is not
162*0Sstevel@tonic-gate 			 * marked OK on its own node - otherwise, different
163*0Sstevel@tonic-gate 			 * nodes would have different nodelists possibly
164*0Sstevel@tonic-gate 			 * causing different nodes to to choose different
165*0Sstevel@tonic-gate 			 * masters.
166*0Sstevel@tonic-gate 			 */
167*0Sstevel@tonic-gate 			if (!(nd->nd_flags & MD_MN_NODE_OK)) {
168*0Sstevel@tonic-gate 				nd = nd->nd_next;
169*0Sstevel@tonic-gate 				continue;
170*0Sstevel@tonic-gate 			}
171*0Sstevel@tonic-gate 			if ((nd->nd_flags & MD_MN_NODE_ALIVE) &&
172*0Sstevel@tonic-gate 			    (nd->nd_flags & MD_MN_NODE_OWN)) {
173*0Sstevel@tonic-gate 				(void) printf(
174*0Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
175*0Sstevel@tonic-gate 				    nd->nd_nodename, gettext("multi-owner"),
176*0Sstevel@tonic-gate 				    gettext("Yes"));
177*0Sstevel@tonic-gate 			} else /* Should never be able to happen */
178*0Sstevel@tonic-gate 			    if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) &&
179*0Sstevel@tonic-gate 			    (nd->nd_flags & MD_MN_NODE_OWN)) {
180*0Sstevel@tonic-gate 				(void) printf(
181*0Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
182*0Sstevel@tonic-gate 				    nd->nd_nodename, gettext("multi-owner"),
183*0Sstevel@tonic-gate 				    gettext("No"));
184*0Sstevel@tonic-gate 			} else if ((nd->nd_flags & MD_MN_NODE_ALIVE) &&
185*0Sstevel@tonic-gate 			    (!(nd->nd_flags & MD_MN_NODE_OWN))) {
186*0Sstevel@tonic-gate 				(void) printf(
187*0Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
188*0Sstevel@tonic-gate 				    nd->nd_nodename, gettext(""),
189*0Sstevel@tonic-gate 				    gettext("Yes"));
190*0Sstevel@tonic-gate 			} else if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) &&
191*0Sstevel@tonic-gate 			    (!(nd->nd_flags & MD_MN_NODE_OWN))) {
192*0Sstevel@tonic-gate 				(void) printf(
193*0Sstevel@tonic-gate 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
194*0Sstevel@tonic-gate 				    nd->nd_nodename, gettext(""),
195*0Sstevel@tonic-gate 				    gettext("No"));
196*0Sstevel@tonic-gate 			}
197*0Sstevel@tonic-gate 			nd = nd->nd_next;
198*0Sstevel@tonic-gate 		}
199*0Sstevel@tonic-gate 	} else {
200*0Sstevel@tonic-gate 		(void) printf("\n%-19.19s %-5.5s\n",
201*0Sstevel@tonic-gate 			gettext("Host"), gettext("Owner"));
202*0Sstevel@tonic-gate 		for (i = 0; i < MD_MAXSIDES; i++) {
203*0Sstevel@tonic-gate 			/* Skip empty slots */
204*0Sstevel@tonic-gate 			if (sd->sd_nodes[i][0] == '\0')
205*0Sstevel@tonic-gate 				continue;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 			/*
208*0Sstevel@tonic-gate 			 * Standard hostname field is 17 bytes but metaset will
209*0Sstevel@tonic-gate 			 * display up to MD_MAX_NODENAME, def in meta_basic.h
210*0Sstevel@tonic-gate 			 */
211*0Sstevel@tonic-gate 			(void) printf("  %-17.*s  %s\n", MD_MAX_NODENAME,
212*0Sstevel@tonic-gate 			    sd->sd_nodes[i], (sd->sd_flags & MD_SR_AUTO_TAKE ?
213*0Sstevel@tonic-gate 				(sd->sd_isown[i] ? gettext("Yes (auto)") :
214*0Sstevel@tonic-gate 				    gettext("No (auto)"))
215*0Sstevel@tonic-gate 				: (sd->sd_isown[i] ? gettext("Yes") : "")));
216*0Sstevel@tonic-gate 		}
217*0Sstevel@tonic-gate 	}
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	if (sd->sd_med.n_cnt > 0)
220*0Sstevel@tonic-gate 		(void) printf("\n%-19.19s %-7.7s\n",
221*0Sstevel@tonic-gate 		    gettext("Mediator Host(s)"), gettext("Aliases"));
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	if ((max_meds = get_max_meds(ep)) == 0)
224*0Sstevel@tonic-gate 		return (-1);
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	for (i = 0; i < max_meds; i++) {
227*0Sstevel@tonic-gate 		if (sd->sd_med.n_lst[i].a_cnt == 0)
228*0Sstevel@tonic-gate 			continue;
229*0Sstevel@tonic-gate 		(void) printf("  %-17.17s   ", sd->sd_med.n_lst[i].a_nm[0]);
230*0Sstevel@tonic-gate 		for (j = 1; j < sd->sd_med.n_lst[i].a_cnt; j++) {
231*0Sstevel@tonic-gate 			(void) printf("%s", sd->sd_med.n_lst[i].a_nm[j]);
232*0Sstevel@tonic-gate 			if (sd->sd_med.n_lst[i].a_cnt - j > 1)
233*0Sstevel@tonic-gate 				(void) printf(gettext(", "));
234*0Sstevel@tonic-gate 		}
235*0Sstevel@tonic-gate 		(void) printf("\n");
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	if (dd) {
239*0Sstevel@tonic-gate 		int	len = 0;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 		/*
243*0Sstevel@tonic-gate 		 * Building a format string on the fly that will
244*0Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
245*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
246*0Sstevel@tonic-gate 		 * looking horrible.
247*0Sstevel@tonic-gate 		 */
248*0Sstevel@tonic-gate 		for (p = dd; p != NULL; p = p->dd_next)
249*0Sstevel@tonic-gate 			len = max(len, strlen(p->dd_dnp->cname));
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 		len += 2;
252*0Sstevel@tonic-gate 		(void) printf("\n%-*.*s %-5.5s\n", len, len,
253*0Sstevel@tonic-gate 		    gettext("Drive"),
254*0Sstevel@tonic-gate 		    gettext("Dbase"));
255*0Sstevel@tonic-gate 		for (p = dd; p != NULL; p = p->dd_next) {
256*0Sstevel@tonic-gate 			(void) printf("\n%-*.*s %-5.5s\n", len, len,
257*0Sstevel@tonic-gate 			    p->dd_dnp->cname,
258*0Sstevel@tonic-gate 			    (p->dd_dbcnt ? gettext("Yes") :
259*0Sstevel@tonic-gate 			    gettext("No")));
260*0Sstevel@tonic-gate 		}
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	return (0);
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate static int
267*0Sstevel@tonic-gate printsets(mdsetname_t *sp, md_error_t *ep)
268*0Sstevel@tonic-gate {
269*0Sstevel@tonic-gate 	int			i;
270*0Sstevel@tonic-gate 	mdsetname_t		*sp1;
271*0Sstevel@tonic-gate 	set_t			max_sets;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	/*
274*0Sstevel@tonic-gate 	 * print setname given.
275*0Sstevel@tonic-gate 	 */
276*0Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
277*0Sstevel@tonic-gate 		if (printset(sp, ep))
278*0Sstevel@tonic-gate 			return (-1);
279*0Sstevel@tonic-gate 		return (0);
280*0Sstevel@tonic-gate 	}
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if ((max_sets = get_max_sets(ep)) == 0)
283*0Sstevel@tonic-gate 		return (-1);
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	/*
286*0Sstevel@tonic-gate 	 * Print all known sets
287*0Sstevel@tonic-gate 	 */
288*0Sstevel@tonic-gate 	for (i = 1; i < max_sets; i++) {
289*0Sstevel@tonic-gate 		if ((sp1 = metasetnosetname(i, ep)) == NULL) {
290*0Sstevel@tonic-gate 			if (! mdiserror(ep, MDE_NO_SET))
291*0Sstevel@tonic-gate 				break;
292*0Sstevel@tonic-gate 			mdclrerror(ep);
293*0Sstevel@tonic-gate 			continue;
294*0Sstevel@tonic-gate 		}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 		if (printset(sp1, ep))
297*0Sstevel@tonic-gate 			break;
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 	if (! mdisok(ep))
300*0Sstevel@tonic-gate 		return (-1);
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	return (0);
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate /*
306*0Sstevel@tonic-gate  * Print the current versionn of the cluster contract private interface.
307*0Sstevel@tonic-gate  */
308*0Sstevel@tonic-gate static void
309*0Sstevel@tonic-gate printclusterversion()
310*0Sstevel@tonic-gate {
311*0Sstevel@tonic-gate 	printf("%s\n", METASETIFVERSION);
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate /*
315*0Sstevel@tonic-gate  * Print the disks that make up the given disk set. This is used
316*0Sstevel@tonic-gate  * exclusively by Sun Cluster and is contract private.
317*0Sstevel@tonic-gate  * Should never be called with sname of a Multinode diskset.
318*0Sstevel@tonic-gate  */
319*0Sstevel@tonic-gate static int
320*0Sstevel@tonic-gate printdisksin(char *sname, md_error_t *ep)
321*0Sstevel@tonic-gate {
322*0Sstevel@tonic-gate 	mdsetname_t	*sp;
323*0Sstevel@tonic-gate 	md_drive_desc	*dd, *p;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 		/*
328*0Sstevel@tonic-gate 		 * During a deletion of a set the associated service is
329*0Sstevel@tonic-gate 		 * put offline. The SC3.0 reservation code calls disksuite
330*0Sstevel@tonic-gate 		 * to find a list of disks associated with the set so that
331*0Sstevel@tonic-gate 		 * it can release the reservation on those disks. In this
332*0Sstevel@tonic-gate 		 * case there won't be any disks or even a set left. So just
333*0Sstevel@tonic-gate 		 * return.
334*0Sstevel@tonic-gate 		 */
335*0Sstevel@tonic-gate 		return (0);
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	if (metaget_setownership(sp, ep) == -1)
339*0Sstevel@tonic-gate 		return (-1);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
342*0Sstevel@tonic-gate 	    ep)) == NULL) && !mdisok(ep))
343*0Sstevel@tonic-gate 		return (-1);
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	for (p = dd; p != NULL; p = p->dd_next)
346*0Sstevel@tonic-gate 		(void) printf("%s\n", p->dd_dnp->rname);
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	return (0);
349*0Sstevel@tonic-gate }
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate static void
352*0Sstevel@tonic-gate parse_printset(int argc, char **argv)
353*0Sstevel@tonic-gate {
354*0Sstevel@tonic-gate 	int		c;
355*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
356*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
357*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
358*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/* reset and parse args */
361*0Sstevel@tonic-gate 	optind = 1;
362*0Sstevel@tonic-gate 	opterr = 1;
363*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "s:")) != -1) {
364*0Sstevel@tonic-gate 		switch (c) {
365*0Sstevel@tonic-gate 		case 's':
366*0Sstevel@tonic-gate 			sname = optarg;
367*0Sstevel@tonic-gate 			break;
368*0Sstevel@tonic-gate 		default:
369*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
370*0Sstevel@tonic-gate 		}
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	argc -= optind;
374*0Sstevel@tonic-gate 	argv += optind;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	if (argc != 0)
377*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
380*0Sstevel@tonic-gate 		mde_perror(ep, "");
381*0Sstevel@tonic-gate 		md_exit(sp, 1);
382*0Sstevel@tonic-gate 	}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	if (printsets(sp, ep) && !mdiserror(ep, MDE_SMF_NO_SERVICE)) {
385*0Sstevel@tonic-gate 		mde_perror(ep, "");
386*0Sstevel@tonic-gate 		md_exit(sp, 1);
387*0Sstevel@tonic-gate 	}
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
390*0Sstevel@tonic-gate 		mde_perror(ep, "");
391*0Sstevel@tonic-gate 		md_exit(sp, 1);
392*0Sstevel@tonic-gate 	}
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	md_exit(sp, 0);
395*0Sstevel@tonic-gate }
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate static void
398*0Sstevel@tonic-gate parse_add(int argc, char **argv)
399*0Sstevel@tonic-gate {
400*0Sstevel@tonic-gate 	int			c,
401*0Sstevel@tonic-gate 				created_set,
402*0Sstevel@tonic-gate 				hosts = FALSE,
403*0Sstevel@tonic-gate 				meds = FALSE,
404*0Sstevel@tonic-gate 				auto_take = FALSE,
405*0Sstevel@tonic-gate 				force_label = FALSE,
406*0Sstevel@tonic-gate 				default_size = TRUE;
407*0Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
408*0Sstevel@tonic-gate 	char			*sname = MD_LOCAL_NAME;
409*0Sstevel@tonic-gate 	md_error_t		status = mdnullerror,
410*0Sstevel@tonic-gate 				*ep = &status;
411*0Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
412*0Sstevel@tonic-gate 	mddrivenamelist_t	*p;
413*0Sstevel@tonic-gate 	daddr_t			dbsize,
414*0Sstevel@tonic-gate 				nblks;
415*0Sstevel@tonic-gate 	mdsetname_t		*local_sp = NULL;
416*0Sstevel@tonic-gate 	int			multi_node = 0;
417*0Sstevel@tonic-gate 	md_set_desc		*sd;
418*0Sstevel@tonic-gate 	rval_e			sdssc_rval;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	/* reset and parse args */
421*0Sstevel@tonic-gate 	optind = 1;
422*0Sstevel@tonic-gate 	opterr = 1;
423*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "MaA:hl:Lms:")) != -1) {
424*0Sstevel@tonic-gate 		switch (c) {
425*0Sstevel@tonic-gate 		case 'M':
426*0Sstevel@tonic-gate 			multi_node = 1;
427*0Sstevel@tonic-gate 			break;
428*0Sstevel@tonic-gate 		case 'A':
429*0Sstevel@tonic-gate 			/* verified sub-option in main */
430*0Sstevel@tonic-gate 			if (strcmp(optarg, "enable") == 0)
431*0Sstevel@tonic-gate 				auto_take = TRUE;
432*0Sstevel@tonic-gate 			break;
433*0Sstevel@tonic-gate 		case 'a':
434*0Sstevel@tonic-gate 			break;
435*0Sstevel@tonic-gate 		case 'h':
436*0Sstevel@tonic-gate 		case 'm':
437*0Sstevel@tonic-gate 			if (meds == TRUE || hosts == TRUE)
438*0Sstevel@tonic-gate 				usage(sp, gettext(
439*0Sstevel@tonic-gate 				    "only one -m or -h option allowed"));
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 			if (default_size == FALSE || force_label == TRUE)
442*0Sstevel@tonic-gate 				usage(sp, gettext(
443*0Sstevel@tonic-gate 				    "conflicting options"));
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 			if (c == 'h')
446*0Sstevel@tonic-gate 				hosts = TRUE;
447*0Sstevel@tonic-gate 			else
448*0Sstevel@tonic-gate 				meds = TRUE;
449*0Sstevel@tonic-gate 			break;
450*0Sstevel@tonic-gate 		case 'l':
451*0Sstevel@tonic-gate 			if (hosts == TRUE || meds == TRUE)
452*0Sstevel@tonic-gate 				usage(sp, gettext(
453*0Sstevel@tonic-gate 				    "conflicting options"));
454*0Sstevel@tonic-gate 			if (sscanf(optarg, "%ld", &dbsize) != 1) {
455*0Sstevel@tonic-gate 				md_eprintf(gettext(
456*0Sstevel@tonic-gate 				    "%s: bad format\n"), optarg);
457*0Sstevel@tonic-gate 				usage(sp, "");
458*0Sstevel@tonic-gate 			}
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 			default_size = FALSE;
461*0Sstevel@tonic-gate 			break;
462*0Sstevel@tonic-gate 		case 'L':
463*0Sstevel@tonic-gate 			/* Same criteria as -l */
464*0Sstevel@tonic-gate 			if (hosts == TRUE || meds == TRUE)
465*0Sstevel@tonic-gate 				usage(sp, gettext(
466*0Sstevel@tonic-gate 				    "conflicting options"));
467*0Sstevel@tonic-gate 			force_label = TRUE;
468*0Sstevel@tonic-gate 			break;
469*0Sstevel@tonic-gate 		case 's':
470*0Sstevel@tonic-gate 			sname = optarg;
471*0Sstevel@tonic-gate 			break;
472*0Sstevel@tonic-gate 		default:
473*0Sstevel@tonic-gate 			usage(sp, gettext(
474*0Sstevel@tonic-gate 			    "unknown options"));
475*0Sstevel@tonic-gate 		}
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	/* Can only use -A enable when creating the single-node set */
479*0Sstevel@tonic-gate 	if (auto_take && hosts != TRUE)
480*0Sstevel@tonic-gate 		usage(sp, gettext("conflicting options"));
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	argc -= optind;
483*0Sstevel@tonic-gate 	argv += optind;
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	/*
486*0Sstevel@tonic-gate 	 * Add hosts
487*0Sstevel@tonic-gate 	 */
488*0Sstevel@tonic-gate 	if (hosts == TRUE) {
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
491*0Sstevel@tonic-gate 			mde_perror(ep, "");
492*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
493*0Sstevel@tonic-gate 		}
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		if (meta_lock(local_sp, TRUE, ep) != 0) {
496*0Sstevel@tonic-gate 			mde_perror(ep, "");
497*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
498*0Sstevel@tonic-gate 		}
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 		/*
501*0Sstevel@tonic-gate 		 * Keep track of Cluster set creation. Need to complete
502*0Sstevel@tonic-gate 		 * the transaction no matter if the set was created or not.
503*0Sstevel@tonic-gate 		 */
504*0Sstevel@tonic-gate 		created_set = 0;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 		/*
507*0Sstevel@tonic-gate 		 * Have no set, cannot take the lock, so only take the
508*0Sstevel@tonic-gate 		 * local lock.
509*0Sstevel@tonic-gate 		 */
510*0Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) == NULL) {
511*0Sstevel@tonic-gate 			sdssc_rval = 0;
512*0Sstevel@tonic-gate 			if (multi_node) {
513*0Sstevel@tonic-gate 				/*
514*0Sstevel@tonic-gate 				 * When running on a cluster system that
515*0Sstevel@tonic-gate 				 * does not support MN disksets, the routine
516*0Sstevel@tonic-gate 				 * sdssc_mo_create_begin will be bound
517*0Sstevel@tonic-gate 				 * to the SVM routine not_bound_error
518*0Sstevel@tonic-gate 				 * which returns SDSSC_NOT_BOUND_ERROR.
519*0Sstevel@tonic-gate 				 *
520*0Sstevel@tonic-gate 				 * When running on a cluster system that
521*0Sstevel@tonic-gate 				 * does support MN disksets, the routine
522*0Sstevel@tonic-gate 				 * sdssc_mo_create_begin will be bound to
523*0Sstevel@tonic-gate 				 * the sdssc_mo_create_begin routine in
524*0Sstevel@tonic-gate 				 * library libsdssc_so.  A call to
525*0Sstevel@tonic-gate 				 * sdssc_mo_create_begin will return with
526*0Sstevel@tonic-gate 				 * either SDSSC_ERROR or SDSSC_OKAY. If
527*0Sstevel@tonic-gate 				 * an SDSSC_OKAY is returned, then the
528*0Sstevel@tonic-gate 				 * cluster framework has allocated a
529*0Sstevel@tonic-gate 				 * set number for this new set that is unique
530*0Sstevel@tonic-gate 				 * across traditional and MN disksets.
531*0Sstevel@tonic-gate 				 * Libmeta will get this unique set number
532*0Sstevel@tonic-gate 				 * by calling sdssc_get_index.
533*0Sstevel@tonic-gate 				 *
534*0Sstevel@tonic-gate 				 * When running on a non-cluster system,
535*0Sstevel@tonic-gate 				 * the routine sdssc_mo_create_begin
536*0Sstevel@tonic-gate 				 * will be bound to the SVM routine
537*0Sstevel@tonic-gate 				 * not_bound which returns SDSSC_NOT_BOUND.
538*0Sstevel@tonic-gate 				 * In this case, all sdssc routines will
539*0Sstevel@tonic-gate 				 * return SDSSC_NOT_BOUND.  No need to check
540*0Sstevel@tonic-gate 				 * for return value of SDSSC_NOT_BOUND since
541*0Sstevel@tonic-gate 				 * the libmeta call to get the set number
542*0Sstevel@tonic-gate 				 * (sdssc_get_index) will also fail with
543*0Sstevel@tonic-gate 				 * SDSSC_NOT_BOUND causing libmeta to
544*0Sstevel@tonic-gate 				 * determine its own set number.
545*0Sstevel@tonic-gate 				 */
546*0Sstevel@tonic-gate 				sdssc_rval = sdssc_mo_create_begin(sname, argc,
547*0Sstevel@tonic-gate 					argv, SDSSC_PICK_SETNO);
548*0Sstevel@tonic-gate 				if (sdssc_rval == SDSSC_NOT_BOUND_ERROR) {
549*0Sstevel@tonic-gate 					mderror(ep, MDE_NOT_MN, NULL);
550*0Sstevel@tonic-gate 					mde_perror(ep,
551*0Sstevel@tonic-gate 					"Cluster node does not support "
552*0Sstevel@tonic-gate 					"multi-owner diskset operations");
553*0Sstevel@tonic-gate 					md_exit(local_sp, 1);
554*0Sstevel@tonic-gate 				} else if (sdssc_rval == SDSSC_ERROR) {
555*0Sstevel@tonic-gate 					mde_perror(ep, "");
556*0Sstevel@tonic-gate 					md_exit(local_sp, 1);
557*0Sstevel@tonic-gate 				}
558*0Sstevel@tonic-gate 			} else {
559*0Sstevel@tonic-gate 				sdssc_rval = sdssc_create_begin(sname, argc,
560*0Sstevel@tonic-gate 					argv, SDSSC_PICK_SETNO);
561*0Sstevel@tonic-gate 				if (sdssc_rval == SDSSC_ERROR) {
562*0Sstevel@tonic-gate 					mde_perror(ep, "");
563*0Sstevel@tonic-gate 					md_exit(local_sp, 1);
564*0Sstevel@tonic-gate 				}
565*0Sstevel@tonic-gate 			}
566*0Sstevel@tonic-gate 			/*
567*0Sstevel@tonic-gate 			 * Created diskset (as opposed to adding a
568*0Sstevel@tonic-gate 			 * host to an existing diskset).
569*0Sstevel@tonic-gate 			 */
570*0Sstevel@tonic-gate 			created_set = 1;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 			sp = Zalloc(sizeof (*sp));
573*0Sstevel@tonic-gate 			sp->setname = Strdup(sname);
574*0Sstevel@tonic-gate 			sp->lockfd = MD_NO_LOCK;
575*0Sstevel@tonic-gate 			mdclrerror(ep);
576*0Sstevel@tonic-gate 		} else {
577*0Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
578*0Sstevel@tonic-gate 				mde_perror(ep, "");
579*0Sstevel@tonic-gate 				md_exit(local_sp, 1);
580*0Sstevel@tonic-gate 			}
581*0Sstevel@tonic-gate 			if (MD_MNSET_DESC(sd)) {
582*0Sstevel@tonic-gate 				multi_node = 1;
583*0Sstevel@tonic-gate 			}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 			/*
586*0Sstevel@tonic-gate 			 * can't add hosts to an existing set & enable
587*0Sstevel@tonic-gate 			 * auto-take
588*0Sstevel@tonic-gate 			 */
589*0Sstevel@tonic-gate 			if (auto_take)
590*0Sstevel@tonic-gate 				usage(sp, gettext("conflicting options"));
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 			/*
593*0Sstevel@tonic-gate 			 * Have a valid set, take the set lock also.
594*0Sstevel@tonic-gate 			 *
595*0Sstevel@tonic-gate 			 * A MN diskset does not use the set meta_lock but
596*0Sstevel@tonic-gate 			 * instead uses the clnt_lock of rpc.metad and the
597*0Sstevel@tonic-gate 			 * suspend/resume feature of the rpc.mdcommd.  Can't
598*0Sstevel@tonic-gate 			 * use set meta_lock since class 1 messages are
599*0Sstevel@tonic-gate 			 * grabbing this lock and if this thread is holding
600*0Sstevel@tonic-gate 			 * the set meta_lock then no rpc.mdcommd suspend
601*0Sstevel@tonic-gate 			 * can occur.
602*0Sstevel@tonic-gate 			 */
603*0Sstevel@tonic-gate 			if (!multi_node) {
604*0Sstevel@tonic-gate 				if (meta_lock(sp, TRUE, ep) != 0) {
605*0Sstevel@tonic-gate 					mde_perror(ep, "");
606*0Sstevel@tonic-gate 					md_exit(local_sp, 1);
607*0Sstevel@tonic-gate 				}
608*0Sstevel@tonic-gate 			}
609*0Sstevel@tonic-gate 		}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 		if (meta_set_addhosts(sp, multi_node, argc, argv, auto_take,
612*0Sstevel@tonic-gate 		    ep)) {
613*0Sstevel@tonic-gate 			if (created_set)
614*0Sstevel@tonic-gate 				sdssc_create_end(sname, SDSSC_CLEANUP);
615*0Sstevel@tonic-gate 			mde_perror(&status, "");
616*0Sstevel@tonic-gate 			if (!multi_node)
617*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
618*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 		if (created_set)
622*0Sstevel@tonic-gate 			sdssc_create_end(sname, SDSSC_COMMIT);
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 		else {
625*0Sstevel@tonic-gate 			/*
626*0Sstevel@tonic-gate 			 * If adding hosts to existing diskset,
627*0Sstevel@tonic-gate 			 * call DCS svcs
628*0Sstevel@tonic-gate 			 */
629*0Sstevel@tonic-gate 			sdssc_add_hosts(sname, argc, argv);
630*0Sstevel@tonic-gate 		}
631*0Sstevel@tonic-gate 		if (!multi_node)
632*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
633*0Sstevel@tonic-gate 		md_exit(local_sp, 0);
634*0Sstevel@tonic-gate 	}
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	/*
637*0Sstevel@tonic-gate 	 * Add mediators
638*0Sstevel@tonic-gate 	 */
639*0Sstevel@tonic-gate 	if (meds == TRUE) {
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) == NULL) {
642*0Sstevel@tonic-gate 			mde_perror(ep, "");
643*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
644*0Sstevel@tonic-gate 		}
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 		if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
647*0Sstevel@tonic-gate 			mde_perror(ep, "");
648*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
649*0Sstevel@tonic-gate 		}
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
652*0Sstevel@tonic-gate 			mde_perror(ep, "");
653*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
654*0Sstevel@tonic-gate 		}
655*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
656*0Sstevel@tonic-gate 			multi_node = 1;
657*0Sstevel@tonic-gate 		}
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 		if (meta_lock(local_sp, TRUE, ep) != 0) {
660*0Sstevel@tonic-gate 			mde_perror(ep, "");
661*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
662*0Sstevel@tonic-gate 		}
663*0Sstevel@tonic-gate 		/*
664*0Sstevel@tonic-gate 		 * A MN diskset does not use the set meta_lock but
665*0Sstevel@tonic-gate 		 * instead uses the clnt_lock of rpc.metad and the
666*0Sstevel@tonic-gate 		 * suspend/resume feature of the rpc.mdcommd.  Can't
667*0Sstevel@tonic-gate 		 * use set meta_lock since class 1 messages are
668*0Sstevel@tonic-gate 		 * grabbing this lock and if this thread is holding
669*0Sstevel@tonic-gate 		 * the set meta_lock then no rpc.mdcommd suspend
670*0Sstevel@tonic-gate 		 * can occur.
671*0Sstevel@tonic-gate 		 */
672*0Sstevel@tonic-gate 		if (!multi_node) {
673*0Sstevel@tonic-gate 			if (meta_lock(sp, TRUE, ep) != 0) {
674*0Sstevel@tonic-gate 				mde_perror(ep, "");
675*0Sstevel@tonic-gate 				md_exit(local_sp, 1);
676*0Sstevel@tonic-gate 			}
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 		if (meta_set_addmeds(sp, argc, argv, ep)) {
680*0Sstevel@tonic-gate 			mde_perror(&status, "");
681*0Sstevel@tonic-gate 			if (!multi_node)
682*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
683*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
684*0Sstevel@tonic-gate 		}
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 		if (!multi_node)
687*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
688*0Sstevel@tonic-gate 		md_exit(local_sp, 0);
689*0Sstevel@tonic-gate 	}
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	/*
692*0Sstevel@tonic-gate 	 * Add drives
693*0Sstevel@tonic-gate 	 */
694*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
695*0Sstevel@tonic-gate 		mde_perror(ep, "");
696*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
697*0Sstevel@tonic-gate 	}
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
700*0Sstevel@tonic-gate 		mde_perror(ep, "");
701*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	/* Determine if diskset is a MN diskset or not */
705*0Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
706*0Sstevel@tonic-gate 		mde_perror(ep, "");
707*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
708*0Sstevel@tonic-gate 	}
709*0Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
710*0Sstevel@tonic-gate 		multi_node = 1;
711*0Sstevel@tonic-gate 	}
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
714*0Sstevel@tonic-gate 		mde_perror(ep, "");
715*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
716*0Sstevel@tonic-gate 	}
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	/* Make sure database size is within limits */
719*0Sstevel@tonic-gate 	if (default_size == FALSE) {
720*0Sstevel@tonic-gate 		if ((multi_node && dbsize < MDDB_MN_MINBLKS) ||
721*0Sstevel@tonic-gate 		    (!multi_node && dbsize < MDDB_MINBLKS))
722*0Sstevel@tonic-gate 			usage(sp, gettext(
723*0Sstevel@tonic-gate 			    "size (-l) is too small"));
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		if ((multi_node && dbsize > MDDB_MN_MAXBLKS) ||
726*0Sstevel@tonic-gate 		    (!multi_node && dbsize > MDDB_MAXBLKS))
727*0Sstevel@tonic-gate 			usage(sp, gettext(
728*0Sstevel@tonic-gate 			    "size (-l) is too big"));
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	/*
732*0Sstevel@tonic-gate 	 * Have a valid set, take the set lock also.
733*0Sstevel@tonic-gate 	 *
734*0Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but
735*0Sstevel@tonic-gate 	 * instead uses the clnt_lock of rpc.metad and the
736*0Sstevel@tonic-gate 	 * suspend/resume feature of the rpc.mdcommd.  Can't
737*0Sstevel@tonic-gate 	 * use set meta_lock since class 1 messages are
738*0Sstevel@tonic-gate 	 * grabbing this lock and if this thread is holding
739*0Sstevel@tonic-gate 	 * the set meta_lock then no rpc.mdcommd suspend
740*0Sstevel@tonic-gate 	 * can occur.
741*0Sstevel@tonic-gate 	 */
742*0Sstevel@tonic-gate 	if (!multi_node) {
743*0Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, ep) != 0) {
744*0Sstevel@tonic-gate 			mde_perror(ep, "");
745*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
746*0Sstevel@tonic-gate 		}
747*0Sstevel@tonic-gate 	}
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	/*
751*0Sstevel@tonic-gate 	 * If using the default size,
752*0Sstevel@tonic-gate 	 *   then let's adjust the default to the minimum
753*0Sstevel@tonic-gate 	 *   size currently in use.
754*0Sstevel@tonic-gate 	 */
755*0Sstevel@tonic-gate 	if (default_size) {
756*0Sstevel@tonic-gate 		dbsize = multi_node ? MD_MN_DBSIZE : MD_DBSIZE;
757*0Sstevel@tonic-gate 		if ((nblks = meta_db_minreplica(sp, ep)) < 0)
758*0Sstevel@tonic-gate 			mdclrerror(ep);
759*0Sstevel@tonic-gate 		else
760*0Sstevel@tonic-gate 			dbsize = nblks;	/* adjust replica size */
761*0Sstevel@tonic-gate 	}
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) {
764*0Sstevel@tonic-gate 		mde_perror(ep, "");
765*0Sstevel@tonic-gate 		if (!multi_node)
766*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
767*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	if (c == 0) {
771*0Sstevel@tonic-gate 		md_perror(gettext(
772*0Sstevel@tonic-gate 		    "No drives specified to add.\n"));
773*0Sstevel@tonic-gate 		if (!multi_node)
774*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
775*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
776*0Sstevel@tonic-gate 	}
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	if (meta_set_adddrives(sp, dnlp, dbsize, force_label, ep)) {
779*0Sstevel@tonic-gate 		metafreedrivenamelist(dnlp);
780*0Sstevel@tonic-gate 		mde_perror(ep, "");
781*0Sstevel@tonic-gate 		if (!multi_node)
782*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
783*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
784*0Sstevel@tonic-gate 	}
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	/*
787*0Sstevel@tonic-gate 	 * MN disksets don't have a device id in the master block
788*0Sstevel@tonic-gate 	 * For traditional disksets, check for the drive device
789*0Sstevel@tonic-gate 	 * id not fitting in the master block
790*0Sstevel@tonic-gate 	 */
791*0Sstevel@tonic-gate 	if (!multi_node) {
792*0Sstevel@tonic-gate 		for (p = dnlp; p != NULL; p = p->next) {
793*0Sstevel@tonic-gate 			int 		fd;
794*0Sstevel@tonic-gate 			ddi_devid_t	devid;
795*0Sstevel@tonic-gate 			mdname_t	*np;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 			np = metaslicename(p->drivenamep, 0, ep);
798*0Sstevel@tonic-gate 			if (np == NULL)
799*0Sstevel@tonic-gate 				continue;
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 			if ((fd = open(np->rname, O_RDONLY | O_NDELAY)) < 0)
802*0Sstevel@tonic-gate 				continue;
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 			if (devid_get(fd, &devid) == 0) {
805*0Sstevel@tonic-gate 				size_t len;
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 				len = devid_sizeof(devid);
808*0Sstevel@tonic-gate 				if (len > (DEV_BSIZE - sizeof (mddb_mb_t)))
809*0Sstevel@tonic-gate 					(void) mddserror(ep,
810*0Sstevel@tonic-gate 					    MDE_DS_NOTSELFIDENTIFY, NULL, NULL,
811*0Sstevel@tonic-gate 					    np->rname, NULL);
812*0Sstevel@tonic-gate 				devid_free(devid);
813*0Sstevel@tonic-gate 			} else {
814*0Sstevel@tonic-gate 				(void) mddserror(ep, MDE_DS_NOTSELFIDENTIFY,
815*0Sstevel@tonic-gate 				    NULL, NULL, np->rname, NULL);
816*0Sstevel@tonic-gate 			}
817*0Sstevel@tonic-gate 			(void) close(fd);
818*0Sstevel@tonic-gate 		}
819*0Sstevel@tonic-gate 	}
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	/*
822*0Sstevel@tonic-gate 	 * MN disksets don't use DCS clustering services.
823*0Sstevel@tonic-gate 	 * For traditional disksets:
824*0Sstevel@tonic-gate 	 * There's not really much we can do here if this call fails.
825*0Sstevel@tonic-gate 	 * The drives have been added to the set and DiskSuite believes
826*0Sstevel@tonic-gate 	 * it owns the drives.
827*0Sstevel@tonic-gate 	 * Relase the set and hope for the best.
828*0Sstevel@tonic-gate 	 */
829*0Sstevel@tonic-gate 	if ((!multi_node) &&
830*0Sstevel@tonic-gate 	    (sdssc_notify_service(sname, Make_Primary) == SDSSC_ERROR)) {
831*0Sstevel@tonic-gate 		meta_set_release(sp, ep);
832*0Sstevel@tonic-gate 		printf(gettext(
833*0Sstevel@tonic-gate 		    "Sun Clustering failed to make set primary\n"));
834*0Sstevel@tonic-gate 	}
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	metafreedrivenamelist(dnlp);
837*0Sstevel@tonic-gate 	if (!multi_node)
838*0Sstevel@tonic-gate 		(void) meta_unlock(sp, ep);
839*0Sstevel@tonic-gate 	md_exit(local_sp, 0);
840*0Sstevel@tonic-gate }
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate static void
843*0Sstevel@tonic-gate parse_balance(int argc, char **argv)
844*0Sstevel@tonic-gate {
845*0Sstevel@tonic-gate 	int		c;
846*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
847*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
848*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
849*0Sstevel@tonic-gate 	md_set_desc	*sd;
850*0Sstevel@tonic-gate 	int		multi_node = 0;
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 	/* reset and parse args */
853*0Sstevel@tonic-gate 	optind = 1;
854*0Sstevel@tonic-gate 	opterr = 1;
855*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Mbs:")) != -1) {
856*0Sstevel@tonic-gate 		switch (c) {
857*0Sstevel@tonic-gate 		case 'M':
858*0Sstevel@tonic-gate 			break;
859*0Sstevel@tonic-gate 		case 'b':
860*0Sstevel@tonic-gate 			break;
861*0Sstevel@tonic-gate 		case 's':
862*0Sstevel@tonic-gate 			sname = optarg;
863*0Sstevel@tonic-gate 			break;
864*0Sstevel@tonic-gate 		default:
865*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
866*0Sstevel@tonic-gate 		}
867*0Sstevel@tonic-gate 	}
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 	argc -= optind;
870*0Sstevel@tonic-gate 	argv += optind;
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	if (argc != 0)
873*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, &status)) == NULL) {
876*0Sstevel@tonic-gate 		mde_perror(&status, "");
877*0Sstevel@tonic-gate 		md_exit(sp, 1);
878*0Sstevel@tonic-gate 	}
879*0Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, &status)) == NULL) {
880*0Sstevel@tonic-gate 		mde_perror(&status, "");
881*0Sstevel@tonic-gate 		md_exit(sp, 1);
882*0Sstevel@tonic-gate 	}
883*0Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd)) {
884*0Sstevel@tonic-gate 		multi_node = 1;
885*0Sstevel@tonic-gate 	}
886*0Sstevel@tonic-gate 	/*
887*0Sstevel@tonic-gate 	 * Have a valid set, take the set lock also.
888*0Sstevel@tonic-gate 	 *
889*0Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but
890*0Sstevel@tonic-gate 	 * instead uses the clnt_lock of rpc.metad and the
891*0Sstevel@tonic-gate 	 * suspend/resume feature of the rpc.mdcommd.  Can't
892*0Sstevel@tonic-gate 	 * use set meta_lock since class 1 messages are
893*0Sstevel@tonic-gate 	 * grabbing this lock and if this thread is holding
894*0Sstevel@tonic-gate 	 * the set meta_lock then no rpc.mdcommd suspend
895*0Sstevel@tonic-gate 	 * can occur.
896*0Sstevel@tonic-gate 	 */
897*0Sstevel@tonic-gate 	if (!multi_node) {
898*0Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, &status) != 0) {
899*0Sstevel@tonic-gate 			mde_perror(&status, "");
900*0Sstevel@tonic-gate 			md_exit(sp, 1);
901*0Sstevel@tonic-gate 		}
902*0Sstevel@tonic-gate 	}
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 	if (meta_set_balance(sp, &status) != 0) {
905*0Sstevel@tonic-gate 		mde_perror(&status, "");
906*0Sstevel@tonic-gate 		md_exit(sp, 1);
907*0Sstevel@tonic-gate 	}
908*0Sstevel@tonic-gate 	md_exit(sp, 0);
909*0Sstevel@tonic-gate }
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate static void
912*0Sstevel@tonic-gate parse_autotake(int argc, char **argv)
913*0Sstevel@tonic-gate {
914*0Sstevel@tonic-gate 	int			c;
915*0Sstevel@tonic-gate 	int			enable = 0;
916*0Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
917*0Sstevel@tonic-gate 	char			*sname = MD_LOCAL_NAME;
918*0Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
919*0Sstevel@tonic-gate 	md_error_t		*ep = &status;
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	/* reset and parse args */
922*0Sstevel@tonic-gate 	optind = 1;
923*0Sstevel@tonic-gate 	opterr = 1;
924*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "A:s:")) != -1) {
925*0Sstevel@tonic-gate 		switch (c) {
926*0Sstevel@tonic-gate 		case 'A':
927*0Sstevel@tonic-gate 			/* verified sub-option in main */
928*0Sstevel@tonic-gate 			if (strcmp(optarg, "enable") == 0)
929*0Sstevel@tonic-gate 				enable = 1;
930*0Sstevel@tonic-gate 			break;
931*0Sstevel@tonic-gate 		case 's':
932*0Sstevel@tonic-gate 			/* verified presence of setname in main */
933*0Sstevel@tonic-gate 			sname = optarg;
934*0Sstevel@tonic-gate 			break;
935*0Sstevel@tonic-gate 		default:
936*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
937*0Sstevel@tonic-gate 		}
938*0Sstevel@tonic-gate 	}
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
941*0Sstevel@tonic-gate 		mde_perror(ep, "");
942*0Sstevel@tonic-gate 		md_exit(sp, 1);
943*0Sstevel@tonic-gate 	}
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, ep) != 0) {
946*0Sstevel@tonic-gate 		mde_perror(ep, "");
947*0Sstevel@tonic-gate 		md_exit(sp, 1);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) != 0) {
951*0Sstevel@tonic-gate 		mde_perror(ep, "");
952*0Sstevel@tonic-gate 		md_exit(sp, 1);
953*0Sstevel@tonic-gate 	}
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 	if (meta_set_auto_take(sp, enable, ep) != 0) {
956*0Sstevel@tonic-gate 		mde_perror(ep, "");
957*0Sstevel@tonic-gate 		md_exit(sp, 1);
958*0Sstevel@tonic-gate 	}
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	md_exit(sp, 0);
961*0Sstevel@tonic-gate }
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate static void
964*0Sstevel@tonic-gate parse_del(int argc, char **argv)
965*0Sstevel@tonic-gate {
966*0Sstevel@tonic-gate 	int			c;
967*0Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
968*0Sstevel@tonic-gate 	char			*sname = MD_LOCAL_NAME;
969*0Sstevel@tonic-gate 	int			hosts = FALSE;
970*0Sstevel@tonic-gate 	int			meds = FALSE;
971*0Sstevel@tonic-gate 	int			forceflg = FALSE;
972*0Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
973*0Sstevel@tonic-gate 	md_error_t		*ep = &status;
974*0Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
975*0Sstevel@tonic-gate 	mdsetname_t		*local_sp = NULL;
976*0Sstevel@tonic-gate 	md_set_desc		*sd;
977*0Sstevel@tonic-gate 	int			multi_node = 0;
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 	/* reset and parse args */
980*0Sstevel@tonic-gate 	optind = 1;
981*0Sstevel@tonic-gate 	opterr = 1;
982*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Mdfhms:")) != -1) {
983*0Sstevel@tonic-gate 		switch (c) {
984*0Sstevel@tonic-gate 		case 'M':
985*0Sstevel@tonic-gate 			break;
986*0Sstevel@tonic-gate 		case 'd':
987*0Sstevel@tonic-gate 			break;
988*0Sstevel@tonic-gate 		case 'f':
989*0Sstevel@tonic-gate 			forceflg = TRUE;
990*0Sstevel@tonic-gate 			break;
991*0Sstevel@tonic-gate 		case 'h':
992*0Sstevel@tonic-gate 		case 'm':
993*0Sstevel@tonic-gate 			if (meds == TRUE || hosts == TRUE)
994*0Sstevel@tonic-gate 				usage(sp, gettext(
995*0Sstevel@tonic-gate 				    "only one -m or -h option allowed"));
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 			if (c == 'h')
998*0Sstevel@tonic-gate 				hosts = TRUE;
999*0Sstevel@tonic-gate 			else
1000*0Sstevel@tonic-gate 				meds = TRUE;
1001*0Sstevel@tonic-gate 			break;
1002*0Sstevel@tonic-gate 		case 's':
1003*0Sstevel@tonic-gate 			sname = optarg;
1004*0Sstevel@tonic-gate 			break;
1005*0Sstevel@tonic-gate 		default:
1006*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1007*0Sstevel@tonic-gate 		}
1008*0Sstevel@tonic-gate 	}
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate 	argc -= optind;
1011*0Sstevel@tonic-gate 	argv += optind;
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
1014*0Sstevel@tonic-gate 		mde_perror(ep, "");
1015*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1016*0Sstevel@tonic-gate 	}
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1019*0Sstevel@tonic-gate 		mde_perror(ep, "");
1020*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1021*0Sstevel@tonic-gate 	}
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1024*0Sstevel@tonic-gate 		mde_perror(ep, "");
1025*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1026*0Sstevel@tonic-gate 	}
1027*0Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd))
1028*0Sstevel@tonic-gate 		multi_node = 1;
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1031*0Sstevel@tonic-gate 		mde_perror(ep, "");
1032*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1033*0Sstevel@tonic-gate 	}
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	/*
1036*0Sstevel@tonic-gate 	 * Have a valid set, take the set lock also.
1037*0Sstevel@tonic-gate 	 *
1038*0Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but
1039*0Sstevel@tonic-gate 	 * instead uses the clnt_lock of rpc.metad and the
1040*0Sstevel@tonic-gate 	 * suspend/resume feature of the rpc.mdcommd.  Can't
1041*0Sstevel@tonic-gate 	 * use set meta_lock since class 1 messages are
1042*0Sstevel@tonic-gate 	 * grabbing this lock and if this thread is holding
1043*0Sstevel@tonic-gate 	 * the set meta_lock then no rpc.mdcommd suspend
1044*0Sstevel@tonic-gate 	 * can occur.
1045*0Sstevel@tonic-gate 	 */
1046*0Sstevel@tonic-gate 	if (!multi_node) {
1047*0Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, ep) != 0) {
1048*0Sstevel@tonic-gate 			mde_perror(ep, "");
1049*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1050*0Sstevel@tonic-gate 		}
1051*0Sstevel@tonic-gate 	}
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 	/*
1054*0Sstevel@tonic-gate 	 * Delete hosts
1055*0Sstevel@tonic-gate 	 */
1056*0Sstevel@tonic-gate 	if (hosts == TRUE) {
1057*0Sstevel@tonic-gate 		if (meta_check_ownership(sp, ep) != 0) {
1058*0Sstevel@tonic-gate 			/*
1059*0Sstevel@tonic-gate 			 * If we don't own the set bail out here otherwise
1060*0Sstevel@tonic-gate 			 * we could delete the node from the DCS service
1061*0Sstevel@tonic-gate 			 * yet not delete the host from the set.
1062*0Sstevel@tonic-gate 			 */
1063*0Sstevel@tonic-gate 			mde_perror(ep, "");
1064*0Sstevel@tonic-gate 			if (!multi_node)
1065*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1066*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1067*0Sstevel@tonic-gate 		}
1068*0Sstevel@tonic-gate 		if (sdssc_delete_hosts(sname, argc, argv) == SDSSC_ERROR) {
1069*0Sstevel@tonic-gate 		    if (!metad_isautotakebyname(sname)) {
1070*0Sstevel@tonic-gate 			/*
1071*0Sstevel@tonic-gate 			 * SC could have been installed after the set was
1072*0Sstevel@tonic-gate 			 * created.  We still want to be able to delete these
1073*0Sstevel@tonic-gate 			 * sets.
1074*0Sstevel@tonic-gate 			 */
1075*0Sstevel@tonic-gate 			md_perror(gettext(
1076*0Sstevel@tonic-gate 			    "Failed to delete hosts from DCS service"));
1077*0Sstevel@tonic-gate 			if (!multi_node)
1078*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1079*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1080*0Sstevel@tonic-gate 		    }
1081*0Sstevel@tonic-gate 		}
1082*0Sstevel@tonic-gate 		if (meta_set_deletehosts(sp, argc, argv, forceflg, ep)) {
1083*0Sstevel@tonic-gate 			if (sdssc_add_hosts(sname, argc, argv) == SDSSC_ERROR) {
1084*0Sstevel@tonic-gate 				(void) printf(gettext(
1085*0Sstevel@tonic-gate 				    "Failed to restore host(s) in DCS "
1086*0Sstevel@tonic-gate 				    "database\n"));
1087*0Sstevel@tonic-gate 			}
1088*0Sstevel@tonic-gate 			mde_perror(ep, "");
1089*0Sstevel@tonic-gate 			if (!multi_node)
1090*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1091*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1092*0Sstevel@tonic-gate 		}
1093*0Sstevel@tonic-gate 		if (!multi_node)
1094*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
1095*0Sstevel@tonic-gate 		md_exit(local_sp, 0);
1096*0Sstevel@tonic-gate 	}
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	/*
1099*0Sstevel@tonic-gate 	 * Delete mediators
1100*0Sstevel@tonic-gate 	 */
1101*0Sstevel@tonic-gate 	if (meds == TRUE) {
1102*0Sstevel@tonic-gate 		if (meta_set_deletemeds(sp, argc, argv, forceflg, ep)) {
1103*0Sstevel@tonic-gate 			mde_perror(ep, "");
1104*0Sstevel@tonic-gate 			if (!multi_node)
1105*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1106*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1107*0Sstevel@tonic-gate 		}
1108*0Sstevel@tonic-gate 		if (!multi_node)
1109*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
1110*0Sstevel@tonic-gate 		md_exit(local_sp, 0);
1111*0Sstevel@tonic-gate 	}
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	/*
1114*0Sstevel@tonic-gate 	 * Delete drives
1115*0Sstevel@tonic-gate 	 */
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate 	if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) {
1118*0Sstevel@tonic-gate 		mde_perror(ep, "");
1119*0Sstevel@tonic-gate 		if (!multi_node)
1120*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
1121*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1122*0Sstevel@tonic-gate 	}
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate 	if (c == 0) {
1125*0Sstevel@tonic-gate 		md_perror(gettext(
1126*0Sstevel@tonic-gate 		    "No drives specified to delete.\n"));
1127*0Sstevel@tonic-gate 		if (!multi_node)
1128*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
1129*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1130*0Sstevel@tonic-gate 	}
1131*0Sstevel@tonic-gate 
1132*0Sstevel@tonic-gate 	if (meta_set_deletedrives(sp, dnlp, forceflg, ep)) {
1133*0Sstevel@tonic-gate 		metafreedrivenamelist(dnlp);
1134*0Sstevel@tonic-gate 		mde_perror(ep, "");
1135*0Sstevel@tonic-gate 		if (!multi_node)
1136*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
1137*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1138*0Sstevel@tonic-gate 	}
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 	metafreedrivenamelist(dnlp);
1141*0Sstevel@tonic-gate 	if (!multi_node)
1142*0Sstevel@tonic-gate 		(void) meta_unlock(sp, ep);
1143*0Sstevel@tonic-gate 	md_exit(local_sp, 0);
1144*0Sstevel@tonic-gate }
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate static void
1147*0Sstevel@tonic-gate parse_isowner(int argc, char **argv)
1148*0Sstevel@tonic-gate {
1149*0Sstevel@tonic-gate 	int		c;
1150*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
1151*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1152*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1153*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
1154*0Sstevel@tonic-gate 	char		*host = NULL;
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 	/* reset and parse args */
1157*0Sstevel@tonic-gate 	optind = 1;
1158*0Sstevel@tonic-gate 	opterr = 1;
1159*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Moh:s:")) != -1) {
1160*0Sstevel@tonic-gate 		switch (c) {
1161*0Sstevel@tonic-gate 		case 'M':
1162*0Sstevel@tonic-gate 			break;
1163*0Sstevel@tonic-gate 		case 'o':
1164*0Sstevel@tonic-gate 			break;
1165*0Sstevel@tonic-gate 		case 'h':
1166*0Sstevel@tonic-gate 			if (host != NULL) {
1167*0Sstevel@tonic-gate 				usage(sp, gettext(
1168*0Sstevel@tonic-gate 				    "only one -h option allowed"));
1169*0Sstevel@tonic-gate 			}
1170*0Sstevel@tonic-gate 			host = optarg;
1171*0Sstevel@tonic-gate 			break;
1172*0Sstevel@tonic-gate 		case 's':
1173*0Sstevel@tonic-gate 			sname = optarg;
1174*0Sstevel@tonic-gate 			break;
1175*0Sstevel@tonic-gate 		default:
1176*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1177*0Sstevel@tonic-gate 		}
1178*0Sstevel@tonic-gate 	}
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate 	argc -= optind;
1181*0Sstevel@tonic-gate 	argv += optind;
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	if (argc != 0)
1184*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
1187*0Sstevel@tonic-gate 		mde_perror(ep, "");
1188*0Sstevel@tonic-gate 		md_exit(sp, 1);
1189*0Sstevel@tonic-gate 	}
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	if (host == NULL) {
1192*0Sstevel@tonic-gate 		if (meta_check_ownership(sp, ep) != 0) {
1193*0Sstevel@tonic-gate 			mde_perror(ep, "");
1194*0Sstevel@tonic-gate 			md_exit(sp, 1);
1195*0Sstevel@tonic-gate 		}
1196*0Sstevel@tonic-gate 	} else {
1197*0Sstevel@tonic-gate 		if (meta_check_ownership_on_host(sp, host, ep) != 0) {
1198*0Sstevel@tonic-gate 			mde_perror(ep, "");
1199*0Sstevel@tonic-gate 			md_exit(sp, 1);
1200*0Sstevel@tonic-gate 		}
1201*0Sstevel@tonic-gate 	}
1202*0Sstevel@tonic-gate 	md_exit(sp, 0);
1203*0Sstevel@tonic-gate }
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate static void
1206*0Sstevel@tonic-gate parse_purge(int argc, char **argv)
1207*0Sstevel@tonic-gate {
1208*0Sstevel@tonic-gate 	int		c;
1209*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
1210*0Sstevel@tonic-gate 	mdsetname_t	*local_sp = NULL;
1211*0Sstevel@tonic-gate 	md_drive_desc	*dd;
1212*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1213*0Sstevel@tonic-gate 	char		*thishost = mynode();
1214*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1215*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
1216*0Sstevel@tonic-gate 	int		bypass_cluster_purge = 0;
1217*0Sstevel@tonic-gate 	int		forceflg = FALSE;
1218*0Sstevel@tonic-gate 	int		ret = 0;
1219*0Sstevel@tonic-gate 	int		multi_node = 0;
1220*0Sstevel@tonic-gate 	md_set_desc		*sd;
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate 	optind = 1;
1223*0Sstevel@tonic-gate 	opterr = 1;
1224*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "C:fPs:")) != -1) {
1225*0Sstevel@tonic-gate 		switch (c) {
1226*0Sstevel@tonic-gate 		case 'M':
1227*0Sstevel@tonic-gate 			break;
1228*0Sstevel@tonic-gate 		case 'C':
1229*0Sstevel@tonic-gate 			bypass_cluster_purge = 1;
1230*0Sstevel@tonic-gate 			break;
1231*0Sstevel@tonic-gate 		case 'f':
1232*0Sstevel@tonic-gate 			forceflg = TRUE;
1233*0Sstevel@tonic-gate 			break;
1234*0Sstevel@tonic-gate 		case 'P':
1235*0Sstevel@tonic-gate 			break;
1236*0Sstevel@tonic-gate 		case 's':
1237*0Sstevel@tonic-gate 			sname = optarg;
1238*0Sstevel@tonic-gate 			break;
1239*0Sstevel@tonic-gate 		default:
1240*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1241*0Sstevel@tonic-gate 		}
1242*0Sstevel@tonic-gate 	}
1243*0Sstevel@tonic-gate 
1244*0Sstevel@tonic-gate 	argc -= optind;
1245*0Sstevel@tonic-gate 	argv += optind;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	if (argc != 0)
1248*0Sstevel@tonic-gate 		usage(sp, gettext("too many arguments"));
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1251*0Sstevel@tonic-gate 		mde_perror(ep, "");
1252*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1253*0Sstevel@tonic-gate 	}
1254*0Sstevel@tonic-gate 
1255*0Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1256*0Sstevel@tonic-gate 		mde_perror(ep, "");
1257*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1258*0Sstevel@tonic-gate 	}
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
1261*0Sstevel@tonic-gate 		mde_perror(ep, "");
1262*0Sstevel@tonic-gate 		md_exit(sp, 1);
1263*0Sstevel@tonic-gate 	}
1264*0Sstevel@tonic-gate 
1265*0Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1266*0Sstevel@tonic-gate 		mde_perror(ep, "");
1267*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1268*0Sstevel@tonic-gate 	}
1269*0Sstevel@tonic-gate 	if (MD_MNSET_DESC(sd))
1270*0Sstevel@tonic-gate 		multi_node = 1;
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	if (!multi_node) {
1273*0Sstevel@tonic-gate 		if (meta_lock(sp, TRUE, ep) != 0) {
1274*0Sstevel@tonic-gate 			mde_perror(ep, "");
1275*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1276*0Sstevel@tonic-gate 		}
1277*0Sstevel@tonic-gate 	}
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	/* Must not own the set if purging it from this host */
1280*0Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) == 0) {
1281*0Sstevel@tonic-gate 		/*
1282*0Sstevel@tonic-gate 		 * Need to see if there are disks in the set, if not then
1283*0Sstevel@tonic-gate 		 * there is no ownership but meta_check_ownership returns 0
1284*0Sstevel@tonic-gate 		 */
1285*0Sstevel@tonic-gate 		dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST), ep);
1286*0Sstevel@tonic-gate 		if (!mdisok(ep)) {
1287*0Sstevel@tonic-gate 			mde_perror(ep, "");
1288*0Sstevel@tonic-gate 			if (!multi_node)
1289*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1290*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1291*0Sstevel@tonic-gate 		}
1292*0Sstevel@tonic-gate 		if (dd != NULL) {
1293*0Sstevel@tonic-gate 			(void) printf(gettext
1294*0Sstevel@tonic-gate 			    ("Must not be owner of the set when purging it\n"));
1295*0Sstevel@tonic-gate 			if (!multi_node)
1296*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1297*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1298*0Sstevel@tonic-gate 		}
1299*0Sstevel@tonic-gate 	}
1300*0Sstevel@tonic-gate 	/*
1301*0Sstevel@tonic-gate 	 * Remove the node from the DCS service
1302*0Sstevel@tonic-gate 	 */
1303*0Sstevel@tonic-gate 	if (!bypass_cluster_purge) {
1304*0Sstevel@tonic-gate 		if (sdssc_delete_hosts(sname, 1, &thishost) == SDSSC_ERROR) {
1305*0Sstevel@tonic-gate 			md_perror(gettext
1306*0Sstevel@tonic-gate 			    ("Failed to purge hosts from DCS service"));
1307*0Sstevel@tonic-gate 			if (!multi_node)
1308*0Sstevel@tonic-gate 				(void) meta_unlock(sp, ep);
1309*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1310*0Sstevel@tonic-gate 		}
1311*0Sstevel@tonic-gate 	}
1312*0Sstevel@tonic-gate 
1313*0Sstevel@tonic-gate 	if ((ret = meta_set_purge(sp, bypass_cluster_purge, forceflg,
1314*0Sstevel@tonic-gate 	    ep)) != 0) {
1315*0Sstevel@tonic-gate 		if (!bypass_cluster_purge) {
1316*0Sstevel@tonic-gate 			if (sdssc_add_hosts(sname, 1, &thishost) ==
1317*0Sstevel@tonic-gate 			    SDSSC_ERROR) {
1318*0Sstevel@tonic-gate 				(void) printf(gettext(
1319*0Sstevel@tonic-gate 				    "Failed to restore host in DCS "
1320*0Sstevel@tonic-gate 				    "database\n"));
1321*0Sstevel@tonic-gate 			}
1322*0Sstevel@tonic-gate 		}
1323*0Sstevel@tonic-gate 		mde_perror(ep, "");
1324*0Sstevel@tonic-gate 		if (!multi_node)
1325*0Sstevel@tonic-gate 			(void) meta_unlock(sp, ep);
1326*0Sstevel@tonic-gate 		md_exit(local_sp, ret);
1327*0Sstevel@tonic-gate 	}
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	if (!multi_node)
1330*0Sstevel@tonic-gate 		(void) meta_unlock(sp, ep);
1331*0Sstevel@tonic-gate 	md_exit(local_sp, 0);
1332*0Sstevel@tonic-gate }
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate static void
1335*0Sstevel@tonic-gate parse_query(int argc, char **argv)
1336*0Sstevel@tonic-gate {
1337*0Sstevel@tonic-gate 	int		c;
1338*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
1339*0Sstevel@tonic-gate 	mddb_dtag_lst_t	*dtlp = NULL;
1340*0Sstevel@tonic-gate 	mddb_dtag_lst_t	*tdtlp;
1341*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1342*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 	/* reset and parse args */
1345*0Sstevel@tonic-gate 	optind = 1;
1346*0Sstevel@tonic-gate 	opterr = 1;
1347*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Mqs:")) != -1) {
1348*0Sstevel@tonic-gate 		switch (c) {
1349*0Sstevel@tonic-gate 		case 'M':
1350*0Sstevel@tonic-gate 			break;
1351*0Sstevel@tonic-gate 		case 'q':
1352*0Sstevel@tonic-gate 			break;
1353*0Sstevel@tonic-gate 		case 's':
1354*0Sstevel@tonic-gate 			sname = optarg;
1355*0Sstevel@tonic-gate 			break;
1356*0Sstevel@tonic-gate 		default:
1357*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1358*0Sstevel@tonic-gate 		}
1359*0Sstevel@tonic-gate 	}
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 	argc -= optind;
1362*0Sstevel@tonic-gate 	argv += optind;
1363*0Sstevel@tonic-gate 
1364*0Sstevel@tonic-gate 	if (argc != 0)
1365*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, &status)) == NULL) {
1368*0Sstevel@tonic-gate 		mde_perror(&status, "");
1369*0Sstevel@tonic-gate 		md_exit(sp, 1);
1370*0Sstevel@tonic-gate 	}
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, &status) != 0) {
1373*0Sstevel@tonic-gate 		mde_perror(&status, "");
1374*0Sstevel@tonic-gate 		md_exit(sp, 1);
1375*0Sstevel@tonic-gate 	}
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 	if (meta_set_query(sp, &dtlp, &status) != 0) {
1378*0Sstevel@tonic-gate 		mde_perror(&status, "");
1379*0Sstevel@tonic-gate 		md_exit(sp, 1);
1380*0Sstevel@tonic-gate 	}
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	if (dtlp != NULL)
1383*0Sstevel@tonic-gate 		(void) printf("The following tag(s) were found:\n");
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 	for (tdtlp = dtlp; tdtlp != NULL; tdtlp = dtlp) {
1386*0Sstevel@tonic-gate 		dtlp = tdtlp->dtl_nx;
1387*0Sstevel@tonic-gate 		(void) printf("%2d - %s - %s", tdtlp->dtl_dt.dt_id,
1388*0Sstevel@tonic-gate 		    tdtlp->dtl_dt.dt_hn,
1389*0Sstevel@tonic-gate 		    ctime((long *)&tdtlp->dtl_dt.dt_tv.tv_sec));
1390*0Sstevel@tonic-gate 		Free(tdtlp);
1391*0Sstevel@tonic-gate 	}
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate 	md_exit(sp, 0);
1394*0Sstevel@tonic-gate }
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate /* Should never be called with sname of a Multinode diskset. */
1397*0Sstevel@tonic-gate static void
1398*0Sstevel@tonic-gate parse_releaseset(int argc, char **argv)
1399*0Sstevel@tonic-gate {
1400*0Sstevel@tonic-gate 	int		c;
1401*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
1402*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1403*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
1404*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1405*0Sstevel@tonic-gate 	int		no_lock = 0;
1406*0Sstevel@tonic-gate 	sdssc_boolean_e	cluster_release = SDSSC_False;
1407*0Sstevel@tonic-gate 	sdssc_version_t	vers;
1408*0Sstevel@tonic-gate 	rval_e		rval;
1409*0Sstevel@tonic-gate 	md_set_desc	*sd;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	/* reset and parse args */
1412*0Sstevel@tonic-gate 	optind = 1;
1413*0Sstevel@tonic-gate 	opterr = 1;
1414*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "C:ns:r")) != -1) {
1415*0Sstevel@tonic-gate 		switch (c) {
1416*0Sstevel@tonic-gate 		case 'C':
1417*0Sstevel@tonic-gate 			cluster_release = SDSSC_True;
1418*0Sstevel@tonic-gate 			break;
1419*0Sstevel@tonic-gate 		case 'n':
1420*0Sstevel@tonic-gate 			no_lock = 1;
1421*0Sstevel@tonic-gate 			break;
1422*0Sstevel@tonic-gate 		case 's':
1423*0Sstevel@tonic-gate 			sname = optarg;
1424*0Sstevel@tonic-gate 			break;
1425*0Sstevel@tonic-gate 		case 'r':
1426*0Sstevel@tonic-gate 			break;
1427*0Sstevel@tonic-gate 		default:
1428*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1429*0Sstevel@tonic-gate 		}
1430*0Sstevel@tonic-gate 	}
1431*0Sstevel@tonic-gate 
1432*0Sstevel@tonic-gate 	argc -= optind;
1433*0Sstevel@tonic-gate 	argv += optind;
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	if (argc > 0)
1436*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate 	memset(&vers, 0, sizeof (vers));
1439*0Sstevel@tonic-gate 
1440*0Sstevel@tonic-gate 	if ((sdssc_version(&vers) == SDSSC_OKAY) &&
1441*0Sstevel@tonic-gate 	    (vers.major == 3) &&
1442*0Sstevel@tonic-gate 	    (cluster_release == SDSSC_False)) {
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 		/*
1445*0Sstevel@tonic-gate 		 * If the release is being done by the user via the CLI
1446*0Sstevel@tonic-gate 		 * we need to notify the DCS to release this node as being
1447*0Sstevel@tonic-gate 		 * the primary. The reason nothing else needs to be done
1448*0Sstevel@tonic-gate 		 * is due to the fact that the reservation code will exec
1449*0Sstevel@tonic-gate 		 * metaset -C release to complete the operation.
1450*0Sstevel@tonic-gate 		 */
1451*0Sstevel@tonic-gate 		rval = sdssc_notify_service(sname, Release_Primary);
1452*0Sstevel@tonic-gate 		if (rval == SDSSC_ERROR) {
1453*0Sstevel@tonic-gate 			printf(gettext(
1454*0Sstevel@tonic-gate 			    "metaset: failed to notify DCS of release\n"));
1455*0Sstevel@tonic-gate 		}
1456*0Sstevel@tonic-gate 		md_exit(NULL, rval == SDSSC_ERROR);
1457*0Sstevel@tonic-gate 	}
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 		/*
1462*0Sstevel@tonic-gate 		 * It's entirely possible for the SC3.0 reservation code
1463*0Sstevel@tonic-gate 		 * to call for DiskSet to release a diskset and have that
1464*0Sstevel@tonic-gate 		 * diskset not exist. During a diskset removal DiskSuite
1465*0Sstevel@tonic-gate 		 * maybe able to remove all traces of the diskset before
1466*0Sstevel@tonic-gate 		 * the reservation code execs metaset -C release in which
1467*0Sstevel@tonic-gate 		 * case the metasetname will fail, but the overall command
1468*0Sstevel@tonic-gate 		 * shouldn't.
1469*0Sstevel@tonic-gate 		 */
1470*0Sstevel@tonic-gate 		if (vers.major == 3)
1471*0Sstevel@tonic-gate 			md_exit(sp, 0);
1472*0Sstevel@tonic-gate 		else {
1473*0Sstevel@tonic-gate 			mde_perror(ep, "");
1474*0Sstevel@tonic-gate 			md_exit(sp, 1);
1475*0Sstevel@tonic-gate 		}
1476*0Sstevel@tonic-gate 	}
1477*0Sstevel@tonic-gate 
1478*0Sstevel@tonic-gate 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1479*0Sstevel@tonic-gate 		mde_perror(ep, "");
1480*0Sstevel@tonic-gate 		md_exit(sp, 1);
1481*0Sstevel@tonic-gate 	}
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate 	if (sd->sd_flags & MD_SR_AUTO_TAKE) {
1484*0Sstevel@tonic-gate 		md_eprintf(gettext("cannot release auto-take diskset\n"));
1485*0Sstevel@tonic-gate 		md_exit(sp, 1);
1486*0Sstevel@tonic-gate 	}
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
1489*0Sstevel@tonic-gate 		if (no_lock) {
1490*0Sstevel@tonic-gate 			mdclrerror(ep);		/* continue */
1491*0Sstevel@tonic-gate 		} else {
1492*0Sstevel@tonic-gate 			mde_perror(ep, "");
1493*0Sstevel@tonic-gate 			md_exit(sp, 10);	/* special errcode */
1494*0Sstevel@tonic-gate 		}
1495*0Sstevel@tonic-gate 	}
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 	if (meta_set_release(sp, ep)) {
1498*0Sstevel@tonic-gate 		mde_perror(ep, "");
1499*0Sstevel@tonic-gate 		md_exit(sp, 1);
1500*0Sstevel@tonic-gate 	}
1501*0Sstevel@tonic-gate 	md_exit(sp, 0);
1502*0Sstevel@tonic-gate }
1503*0Sstevel@tonic-gate 
1504*0Sstevel@tonic-gate /* Should never be called with sname of a Multinode diskset. */
1505*0Sstevel@tonic-gate static void
1506*0Sstevel@tonic-gate parse_takeset(int argc, char **argv)
1507*0Sstevel@tonic-gate {
1508*0Sstevel@tonic-gate 	int		c;
1509*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
1510*0Sstevel@tonic-gate 	int		flags = 0;
1511*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1512*0Sstevel@tonic-gate 	mhd_mhiargs_t	mhiargs;
1513*0Sstevel@tonic-gate 	char 		*cp = NULL;
1514*0Sstevel@tonic-gate 	int		pos = -1;	/* position of timeout value */
1515*0Sstevel@tonic-gate 	int		usetag = 0;
1516*0Sstevel@tonic-gate 	static char	*nullopts[] = { NULL };
1517*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1518*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
1519*0Sstevel@tonic-gate 	int		no_lock = 0;
1520*0Sstevel@tonic-gate 	sdssc_boolean_e	cluster_take = SDSSC_False;
1521*0Sstevel@tonic-gate 	sdssc_version_t	vers;
1522*0Sstevel@tonic-gate 	rval_e		rval;
1523*0Sstevel@tonic-gate 
1524*0Sstevel@tonic-gate 	/* reset and parse args */
1525*0Sstevel@tonic-gate 	optind = 1;
1526*0Sstevel@tonic-gate 	opterr = 1;
1527*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "C:fns:tu:y")) != -1) {
1528*0Sstevel@tonic-gate 		switch (c) {
1529*0Sstevel@tonic-gate 		case 'C':
1530*0Sstevel@tonic-gate 			cluster_take = SDSSC_True;
1531*0Sstevel@tonic-gate 			break;
1532*0Sstevel@tonic-gate 		case 'f':
1533*0Sstevel@tonic-gate 			flags |= TAKE_FORCE;
1534*0Sstevel@tonic-gate 			break;
1535*0Sstevel@tonic-gate 		case 'n':
1536*0Sstevel@tonic-gate 			no_lock = 1;
1537*0Sstevel@tonic-gate 			break;
1538*0Sstevel@tonic-gate 		case 's':
1539*0Sstevel@tonic-gate 			sname = optarg;
1540*0Sstevel@tonic-gate 			break;
1541*0Sstevel@tonic-gate 		case 't':
1542*0Sstevel@tonic-gate 			break;
1543*0Sstevel@tonic-gate 		case 'u':
1544*0Sstevel@tonic-gate 			usetag = atoi(optarg);
1545*0Sstevel@tonic-gate 			flags |= TAKE_USETAG;
1546*0Sstevel@tonic-gate 			break;
1547*0Sstevel@tonic-gate 		case 'y':
1548*0Sstevel@tonic-gate 			flags |= TAKE_USEIT;
1549*0Sstevel@tonic-gate 			break;
1550*0Sstevel@tonic-gate 		default:
1551*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1552*0Sstevel@tonic-gate 		}
1553*0Sstevel@tonic-gate 	}
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate 	mhiargs = defmhiargs;
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 	argc -= optind;
1558*0Sstevel@tonic-gate 	argv += optind;
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate 	if (argc > 1)
1561*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate 	/*
1564*0Sstevel@tonic-gate 	 * If we have a list of timeout value overrides, handle it here
1565*0Sstevel@tonic-gate 	 */
1566*0Sstevel@tonic-gate 	while (argv[0] != NULL && *argv[0] != '\0') {
1567*0Sstevel@tonic-gate 		/*
1568*0Sstevel@tonic-gate 		 * The use of the nullopts[] "token list" here is to make
1569*0Sstevel@tonic-gate 		 * getsubopts() simply parse a comma separated list
1570*0Sstevel@tonic-gate 		 * returning either "" or the contents of the field, the
1571*0Sstevel@tonic-gate 		 * end condition is exaustion of the initial string, which
1572*0Sstevel@tonic-gate 		 * is modified in the process.
1573*0Sstevel@tonic-gate 		 */
1574*0Sstevel@tonic-gate 		(void) getsubopt(&argv[0], nullopts, &cp);
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 		c = 0;			/* re-use c as temp value of timeout */
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 		if (*cp != '-')		/* '-' uses default */
1579*0Sstevel@tonic-gate 			c = atoi(cp);
1580*0Sstevel@tonic-gate 
1581*0Sstevel@tonic-gate 		if (c < 0) {
1582*0Sstevel@tonic-gate 			usage(sp, gettext(
1583*0Sstevel@tonic-gate 			    "time out values must be > 0"));
1584*0Sstevel@tonic-gate 		}
1585*0Sstevel@tonic-gate 
1586*0Sstevel@tonic-gate 		if (++pos > 3) {
1587*0Sstevel@tonic-gate 			usage(sp, gettext(
1588*0Sstevel@tonic-gate 			    "too many timeout values specified."));
1589*0Sstevel@tonic-gate 		}
1590*0Sstevel@tonic-gate 
1591*0Sstevel@tonic-gate 		if (c == 0)		/* 0 or "" field uses default */
1592*0Sstevel@tonic-gate 			continue;
1593*0Sstevel@tonic-gate 
1594*0Sstevel@tonic-gate 		/*
1595*0Sstevel@tonic-gate 		 * Assign temp value to appropriate structure member based on
1596*0Sstevel@tonic-gate 		 * its position in the comma separated list.
1597*0Sstevel@tonic-gate 		 */
1598*0Sstevel@tonic-gate 		switch (pos) {
1599*0Sstevel@tonic-gate 		    case 0:
1600*0Sstevel@tonic-gate 			mhiargs.mh_ff = c;
1601*0Sstevel@tonic-gate 			break;
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 		    case 1:
1604*0Sstevel@tonic-gate 			mhiargs.mh_tk.reinstate_resv_delay = c;
1605*0Sstevel@tonic-gate 			break;
1606*0Sstevel@tonic-gate 
1607*0Sstevel@tonic-gate 		    case 2:
1608*0Sstevel@tonic-gate 			mhiargs.mh_tk.min_ownership_delay = c;
1609*0Sstevel@tonic-gate 			break;
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 		    case 3:
1612*0Sstevel@tonic-gate 			mhiargs.mh_tk.max_ownership_delay = c;
1613*0Sstevel@tonic-gate 			break;
1614*0Sstevel@tonic-gate 		}
1615*0Sstevel@tonic-gate 	}
1616*0Sstevel@tonic-gate 
1617*0Sstevel@tonic-gate 	memset(&vers, 0, sizeof (vers));
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 	if ((sdssc_version(&vers) == SDSSC_OKAY) &&
1620*0Sstevel@tonic-gate 	    (vers.major == 3) &&
1621*0Sstevel@tonic-gate 	    (cluster_take == SDSSC_False)) {
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 		/*
1624*0Sstevel@tonic-gate 		 * If the take is beging done by the user via the CLI we need
1625*0Sstevel@tonic-gate 		 * to notify the DCS to make this current node the primary.
1626*0Sstevel@tonic-gate 		 * The SC3.0 reservation code will in turn exec metaset with
1627*0Sstevel@tonic-gate 		 * the -C take arg to complete this operation.
1628*0Sstevel@tonic-gate 		 */
1629*0Sstevel@tonic-gate 		if ((rval = sdssc_notify_service(sname, Make_Primary)) ==
1630*0Sstevel@tonic-gate 		    SDSSC_ERROR) {
1631*0Sstevel@tonic-gate 			printf(gettext(
1632*0Sstevel@tonic-gate 			    "metaset: failed to notify DCS of take\n"));
1633*0Sstevel@tonic-gate 		}
1634*0Sstevel@tonic-gate 		md_exit(NULL, rval == SDSSC_ERROR);
1635*0Sstevel@tonic-gate 	}
1636*0Sstevel@tonic-gate 
1637*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
1638*0Sstevel@tonic-gate 		mde_perror(ep, "");
1639*0Sstevel@tonic-gate 		md_exit(sp, 1);
1640*0Sstevel@tonic-gate 	}
1641*0Sstevel@tonic-gate 
1642*0Sstevel@tonic-gate 	if ((vers.major == 3) && (meta_check_ownership(sp, ep) == 0)) {
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 		/*
1645*0Sstevel@tonic-gate 		 * If we're running in a cluster environment and this
1646*0Sstevel@tonic-gate 		 * node already owns the set. Don't bother trying to
1647*0Sstevel@tonic-gate 		 * take the set again. There's one case where an adminstrator
1648*0Sstevel@tonic-gate 		 * is adding disks to a set for the first time. metaset
1649*0Sstevel@tonic-gate 		 * will take the ownership of the set at that point. During
1650*0Sstevel@tonic-gate 		 * that add operation SC3.0 notices activity on the device
1651*0Sstevel@tonic-gate 		 * and also tries to perform a take operation. The SC3.0 take
1652*0Sstevel@tonic-gate 		 * will fail because the adminstrative add has the set locked
1653*0Sstevel@tonic-gate 		 */
1654*0Sstevel@tonic-gate 		md_exit(sp, 0);
1655*0Sstevel@tonic-gate 	}
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
1658*0Sstevel@tonic-gate 		if (no_lock) {
1659*0Sstevel@tonic-gate 			mdclrerror(ep);
1660*0Sstevel@tonic-gate 		} else {
1661*0Sstevel@tonic-gate 			mde_perror(ep, "");
1662*0Sstevel@tonic-gate 			md_exit(sp, 10);	/* special errcode */
1663*0Sstevel@tonic-gate 		}
1664*0Sstevel@tonic-gate 	}
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 	if (meta_set_take(sp, &mhiargs, flags, usetag, &status)) {
1667*0Sstevel@tonic-gate 		mde_perror(&status, "");
1668*0Sstevel@tonic-gate 		if (mdismddberror(&status, MDE_DB_TAGDATA))
1669*0Sstevel@tonic-gate 			md_exit(sp, 2);
1670*0Sstevel@tonic-gate 		if (mdismddberror(&status, MDE_DB_ACCOK))
1671*0Sstevel@tonic-gate 			md_exit(sp, 3);
1672*0Sstevel@tonic-gate 		if (mdismddberror(&status, MDE_DB_STALE))
1673*0Sstevel@tonic-gate 			md_exit(sp, 66);
1674*0Sstevel@tonic-gate 		md_exit(sp, 1);
1675*0Sstevel@tonic-gate 	}
1676*0Sstevel@tonic-gate 	md_exit(sp, 0);
1677*0Sstevel@tonic-gate }
1678*0Sstevel@tonic-gate 
1679*0Sstevel@tonic-gate /*
1680*0Sstevel@tonic-gate  * Joins a node to a specific set or to all multinode disksets known
1681*0Sstevel@tonic-gate  * by this node.  If set is specified then caller should have verified
1682*0Sstevel@tonic-gate  * that the set is a multinode diskset.
1683*0Sstevel@tonic-gate  *
1684*0Sstevel@tonic-gate  * If an error occurs, metaset exits with a 1.
1685*0Sstevel@tonic-gate  * If there is no error, metaset exits with a 0.
1686*0Sstevel@tonic-gate  */
1687*0Sstevel@tonic-gate static void
1688*0Sstevel@tonic-gate parse_joinset(int argc, char **argv)
1689*0Sstevel@tonic-gate {
1690*0Sstevel@tonic-gate 	int		c;
1691*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL, *local_sp = NULL;
1692*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1693*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1694*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
1695*0Sstevel@tonic-gate 	md_set_desc	*sd;
1696*0Sstevel@tonic-gate 	char		buf[BUFSIZ];
1697*0Sstevel@tonic-gate 	char		*p = buf;
1698*0Sstevel@tonic-gate 	set_t		max_sets, setno;
1699*0Sstevel@tonic-gate 	int		err, cumm_err = 0;
1700*0Sstevel@tonic-gate 	size_t		bufsz;
1701*0Sstevel@tonic-gate 
1702*0Sstevel@tonic-gate 	bufsz = sizeof (buf);
1703*0Sstevel@tonic-gate 	/* reset and parse args */
1704*0Sstevel@tonic-gate 	optind = 1;
1705*0Sstevel@tonic-gate 	opterr = 1;
1706*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Ms:j")) != -1) {
1707*0Sstevel@tonic-gate 		switch (c) {
1708*0Sstevel@tonic-gate 		case 'M':
1709*0Sstevel@tonic-gate 			break;
1710*0Sstevel@tonic-gate 		case 'j':
1711*0Sstevel@tonic-gate 			break;
1712*0Sstevel@tonic-gate 		case 's':
1713*0Sstevel@tonic-gate 			sname = optarg;
1714*0Sstevel@tonic-gate 			break;
1715*0Sstevel@tonic-gate 		default:
1716*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1717*0Sstevel@tonic-gate 		}
1718*0Sstevel@tonic-gate 	}
1719*0Sstevel@tonic-gate 
1720*0Sstevel@tonic-gate 	argc -= optind;
1721*0Sstevel@tonic-gate 	argv += optind;
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	if (argc > 1)
1724*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
1725*0Sstevel@tonic-gate 
1726*0Sstevel@tonic-gate 	/*
1727*0Sstevel@tonic-gate 	 * If no setname option was used, then join all disksets
1728*0Sstevel@tonic-gate 	 * that this node knows about.   Attempt to join all
1729*0Sstevel@tonic-gate 	 * disksets that this node knows about.
1730*0Sstevel@tonic-gate 	 *
1731*0Sstevel@tonic-gate 	 * Additional text is added to the error messages during
1732*0Sstevel@tonic-gate 	 * this section of code in order to help the user understand
1733*0Sstevel@tonic-gate 	 * why the 'join of all sets' failed and which set caused
1734*0Sstevel@tonic-gate 	 * the failure.
1735*0Sstevel@tonic-gate 	 */
1736*0Sstevel@tonic-gate 
1737*0Sstevel@tonic-gate 	/*
1738*0Sstevel@tonic-gate 	 * Hold local set lock throughout this call to keep
1739*0Sstevel@tonic-gate 	 * other actions from interfering (such as creating a new
1740*0Sstevel@tonic-gate 	 * set, etc.).
1741*0Sstevel@tonic-gate 	 */
1742*0Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1743*0Sstevel@tonic-gate 		mde_perror(ep, "");
1744*0Sstevel@tonic-gate 		md_exit(sp, 1);
1745*0Sstevel@tonic-gate 	}
1746*0Sstevel@tonic-gate 
1747*0Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1748*0Sstevel@tonic-gate 		mde_perror(ep, "");
1749*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1750*0Sstevel@tonic-gate 	}
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) == 0) {
1753*0Sstevel@tonic-gate 		/*
1754*0Sstevel@tonic-gate 		 * If no set name is given, then walk through all sets
1755*0Sstevel@tonic-gate 		 * on this node which could include:
1756*0Sstevel@tonic-gate 		 * 	- MN disksets
1757*0Sstevel@tonic-gate 		 *	- traditional disksets
1758*0Sstevel@tonic-gate 		 *	- non-existent disksets
1759*0Sstevel@tonic-gate 		 * Attempt to join the MN disksets.
1760*0Sstevel@tonic-gate 		 * If the join of one set fails, print out an error message
1761*0Sstevel@tonic-gate 		 * about that set and continue the walk.
1762*0Sstevel@tonic-gate 		 */
1763*0Sstevel@tonic-gate 		if ((max_sets = get_max_sets(ep)) == 0) {
1764*0Sstevel@tonic-gate 			mde_perror(ep, "");
1765*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1766*0Sstevel@tonic-gate 		}
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 		/* Start walking through all possible disksets */
1769*0Sstevel@tonic-gate 		for (setno = 1; setno < max_sets; setno++) {
1770*0Sstevel@tonic-gate 			if ((sp = metasetnosetname(setno, ep)) == NULL) {
1771*0Sstevel@tonic-gate 				if (mdiserror(ep, MDE_NO_SET)) {
1772*0Sstevel@tonic-gate 					/* No set for this setno - continue */
1773*0Sstevel@tonic-gate 					mdclrerror(ep);
1774*0Sstevel@tonic-gate 					continue;
1775*0Sstevel@tonic-gate 				} else {
1776*0Sstevel@tonic-gate 					(void) sprintf(p, gettext(
1777*0Sstevel@tonic-gate 					"Unable to get set %d information"),
1778*0Sstevel@tonic-gate 					    setno);
1779*0Sstevel@tonic-gate 					mde_perror(ep, p);
1780*0Sstevel@tonic-gate 					cumm_err = 1;
1781*0Sstevel@tonic-gate 					mdclrerror(ep);
1782*0Sstevel@tonic-gate 					continue;
1783*0Sstevel@tonic-gate 				}
1784*0Sstevel@tonic-gate 			}
1785*0Sstevel@tonic-gate 
1786*0Sstevel@tonic-gate 			/* If setname is there, set desc should exist. */
1787*0Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1788*0Sstevel@tonic-gate 				(void) snprintf(p, bufsz, gettext(
1789*0Sstevel@tonic-gate 				    "Unable to get set %s desc information"),
1790*0Sstevel@tonic-gate 				    sp->setname);
1791*0Sstevel@tonic-gate 				mde_perror(ep, p);
1792*0Sstevel@tonic-gate 				cumm_err = 1;
1793*0Sstevel@tonic-gate 				mdclrerror(ep);
1794*0Sstevel@tonic-gate 				continue;
1795*0Sstevel@tonic-gate 			}
1796*0Sstevel@tonic-gate 
1797*0Sstevel@tonic-gate 			/* Only check MN disksets */
1798*0Sstevel@tonic-gate 			if (!MD_MNSET_DESC(sd)) {
1799*0Sstevel@tonic-gate 				continue;
1800*0Sstevel@tonic-gate 			}
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 			/*
1803*0Sstevel@tonic-gate 			 * Return value of 0 is success.
1804*0Sstevel@tonic-gate 			 * Return value of -1 means a failure.
1805*0Sstevel@tonic-gate 			 * Return value of -2 means set could not be
1806*0Sstevel@tonic-gate 			 * joined, but shouldn't cause an error.
1807*0Sstevel@tonic-gate 			 * Reasons would be:
1808*0Sstevel@tonic-gate 			 * 	- no drives in set
1809*0Sstevel@tonic-gate 			 * 	- node already joined to set
1810*0Sstevel@tonic-gate 			 * Return value of -3 means joined stale set.
1811*0Sstevel@tonic-gate 			 * Can't check for all reasons here
1812*0Sstevel@tonic-gate 			 * since set isn't locked yet across all
1813*0Sstevel@tonic-gate 			 * nodes in the cluster.  The call
1814*0Sstevel@tonic-gate 			 * to libmeta routine, meta_set_join, will
1815*0Sstevel@tonic-gate 			 * lock across the cluster and perform
1816*0Sstevel@tonic-gate 			 * the checks.
1817*0Sstevel@tonic-gate 			 */
1818*0Sstevel@tonic-gate 			if ((err = meta_set_join(sp, ep)) == -1) {
1819*0Sstevel@tonic-gate 				/* Print error of diskset join failure */
1820*0Sstevel@tonic-gate 				(void) snprintf(p, bufsz,
1821*0Sstevel@tonic-gate 				    gettext("Join to diskset %s failed"),
1822*0Sstevel@tonic-gate 				    sp->setname);
1823*0Sstevel@tonic-gate 				mde_perror(ep, p);
1824*0Sstevel@tonic-gate 				cumm_err = 1;
1825*0Sstevel@tonic-gate 				mdclrerror(ep);
1826*0Sstevel@tonic-gate 				continue;
1827*0Sstevel@tonic-gate 			}
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate 			if (err == -3) {
1830*0Sstevel@tonic-gate 				/* Print error of diskset join failure */
1831*0Sstevel@tonic-gate 				(void) snprintf(p, bufsz,
1832*0Sstevel@tonic-gate 				    gettext("Joined to stale diskset %s"),
1833*0Sstevel@tonic-gate 				    sp->setname);
1834*0Sstevel@tonic-gate 				mde_perror(ep, p);
1835*0Sstevel@tonic-gate 				mdclrerror(ep);
1836*0Sstevel@tonic-gate 			}
1837*0Sstevel@tonic-gate 
1838*0Sstevel@tonic-gate 			mdclrerror(ep);
1839*0Sstevel@tonic-gate 		}
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate 		md_exit(local_sp, cumm_err);
1842*0Sstevel@tonic-gate 	}
1843*0Sstevel@tonic-gate 
1844*0Sstevel@tonic-gate 	/*
1845*0Sstevel@tonic-gate 	 * Code for a specific set is much simpler.
1846*0Sstevel@tonic-gate 	 * Error messages don't need extra text since specific setname
1847*0Sstevel@tonic-gate 	 * was used.
1848*0Sstevel@tonic-gate 	 * Don't need to lock the local set, just the specific set given.
1849*0Sstevel@tonic-gate 	 */
1850*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
1851*0Sstevel@tonic-gate 		mde_perror(ep, "");
1852*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1853*0Sstevel@tonic-gate 	}
1854*0Sstevel@tonic-gate 
1855*0Sstevel@tonic-gate 	/*
1856*0Sstevel@tonic-gate 	 * Fail command if meta_set_join returns -1.
1857*0Sstevel@tonic-gate 	 *
1858*0Sstevel@tonic-gate 	 * Return of 0 means that node joined set.
1859*0Sstevel@tonic-gate 	 *
1860*0Sstevel@tonic-gate 	 * Return of -2 means that node was unable to
1861*0Sstevel@tonic-gate 	 * join a set since that set had no drives
1862*0Sstevel@tonic-gate 	 * or that had already joined the set.  No
1863*0Sstevel@tonic-gate 	 * need to fail the command for these reasons.
1864*0Sstevel@tonic-gate 	 *
1865*0Sstevel@tonic-gate 	 * Return of -3 means that set is stale.
1866*0Sstevel@tonic-gate 	 * Return a value of 66 to historically match traditional disksets.
1867*0Sstevel@tonic-gate 	 */
1868*0Sstevel@tonic-gate 	if ((err = meta_set_join(sp, ep)) == -1) {
1869*0Sstevel@tonic-gate 		mde_perror(&status, "");
1870*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1871*0Sstevel@tonic-gate 	}
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 	if (err == -3) {
1874*0Sstevel@tonic-gate 		/* Print error of diskset join failure */
1875*0Sstevel@tonic-gate 		(void) snprintf(p, bufsz,
1876*0Sstevel@tonic-gate 		    gettext("Joined to stale diskset %s"),
1877*0Sstevel@tonic-gate 		    sp->setname);
1878*0Sstevel@tonic-gate 		mde_perror(&status, "");
1879*0Sstevel@tonic-gate 		md_exit(local_sp, 66);
1880*0Sstevel@tonic-gate 	}
1881*0Sstevel@tonic-gate 
1882*0Sstevel@tonic-gate 	md_exit(local_sp, 0);
1883*0Sstevel@tonic-gate }
1884*0Sstevel@tonic-gate 
1885*0Sstevel@tonic-gate /*
1886*0Sstevel@tonic-gate  * Withdraws a node from a specific set or from all multinode disksets known
1887*0Sstevel@tonic-gate  * by this node.  If set is specified then caller should have verified
1888*0Sstevel@tonic-gate  * that the set is a multinode diskset.
1889*0Sstevel@tonic-gate  *
1890*0Sstevel@tonic-gate  * If an error occurs, metaset exits with a 1.
1891*0Sstevel@tonic-gate  * If there is no error, metaset exits with a 0.
1892*0Sstevel@tonic-gate  */
1893*0Sstevel@tonic-gate static void
1894*0Sstevel@tonic-gate parse_withdrawset(int argc, char **argv)
1895*0Sstevel@tonic-gate {
1896*0Sstevel@tonic-gate 	int		c;
1897*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL, *local_sp = NULL;
1898*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
1899*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1900*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
1901*0Sstevel@tonic-gate 	char		buf[BUFSIZ];
1902*0Sstevel@tonic-gate 	char		*p = buf;
1903*0Sstevel@tonic-gate 	md_set_desc	*sd;
1904*0Sstevel@tonic-gate 	set_t		max_sets, setno;
1905*0Sstevel@tonic-gate 	int		err, cumm_err = 0;
1906*0Sstevel@tonic-gate 	size_t		bufsz;
1907*0Sstevel@tonic-gate 
1908*0Sstevel@tonic-gate 	bufsz = sizeof (buf);
1909*0Sstevel@tonic-gate 	/* reset and parse args */
1910*0Sstevel@tonic-gate 	optind = 1;
1911*0Sstevel@tonic-gate 	opterr = 1;
1912*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Ms:w")) != -1) {
1913*0Sstevel@tonic-gate 		switch (c) {
1914*0Sstevel@tonic-gate 		case 'M':
1915*0Sstevel@tonic-gate 			break;
1916*0Sstevel@tonic-gate 		case 'w':
1917*0Sstevel@tonic-gate 			break;
1918*0Sstevel@tonic-gate 		case 's':
1919*0Sstevel@tonic-gate 			sname = optarg;
1920*0Sstevel@tonic-gate 			break;
1921*0Sstevel@tonic-gate 		default:
1922*0Sstevel@tonic-gate 			usage(sp, gettext("unknown options"));
1923*0Sstevel@tonic-gate 		}
1924*0Sstevel@tonic-gate 	}
1925*0Sstevel@tonic-gate 
1926*0Sstevel@tonic-gate 	argc -= optind;
1927*0Sstevel@tonic-gate 	argv += optind;
1928*0Sstevel@tonic-gate 
1929*0Sstevel@tonic-gate 	if (argc > 1)
1930*0Sstevel@tonic-gate 		usage(sp, gettext("too many args"));
1931*0Sstevel@tonic-gate 
1932*0Sstevel@tonic-gate 	/*
1933*0Sstevel@tonic-gate 	 * If no setname option was used, then withdraw from all disksets
1934*0Sstevel@tonic-gate 	 * that this node knows about.
1935*0Sstevel@tonic-gate 	 *
1936*0Sstevel@tonic-gate 	 * Additional text is added to the error messages during
1937*0Sstevel@tonic-gate 	 * this section of code in order to help the user understand
1938*0Sstevel@tonic-gate 	 * why the 'withdraw from all sets' failed and which set caused
1939*0Sstevel@tonic-gate 	 * the failure.
1940*0Sstevel@tonic-gate 	 */
1941*0Sstevel@tonic-gate 
1942*0Sstevel@tonic-gate 	/*
1943*0Sstevel@tonic-gate 	 * Hold local set lock throughout this call to keep
1944*0Sstevel@tonic-gate 	 * other actions from interfering (such as creating a new
1945*0Sstevel@tonic-gate 	 * set, etc.).
1946*0Sstevel@tonic-gate 	 */
1947*0Sstevel@tonic-gate 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1948*0Sstevel@tonic-gate 		mde_perror(ep, "");
1949*0Sstevel@tonic-gate 		md_exit(sp, 1);
1950*0Sstevel@tonic-gate 	}
1951*0Sstevel@tonic-gate 
1952*0Sstevel@tonic-gate 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1953*0Sstevel@tonic-gate 		mde_perror(ep, "");
1954*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
1955*0Sstevel@tonic-gate 	}
1956*0Sstevel@tonic-gate 
1957*0Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) == 0) {
1958*0Sstevel@tonic-gate 		/*
1959*0Sstevel@tonic-gate 		 * If no set name is given, then walk through all sets
1960*0Sstevel@tonic-gate 		 * on this node which could include:
1961*0Sstevel@tonic-gate 		 * 	- MN disksets
1962*0Sstevel@tonic-gate 		 *	- traditional disksets
1963*0Sstevel@tonic-gate 		 *	- non-existent disksets
1964*0Sstevel@tonic-gate 		 * Attempt to withdraw from the MN disksets.
1965*0Sstevel@tonic-gate 		 * If the withdraw of one set fails, print out an error
1966*0Sstevel@tonic-gate 		 * message about that set and continue the walk.
1967*0Sstevel@tonic-gate 		 */
1968*0Sstevel@tonic-gate 		if ((max_sets = get_max_sets(ep)) == 0) {
1969*0Sstevel@tonic-gate 			mde_perror(ep, "");
1970*0Sstevel@tonic-gate 			md_exit(local_sp, 1);
1971*0Sstevel@tonic-gate 		}
1972*0Sstevel@tonic-gate 
1973*0Sstevel@tonic-gate 		/* Start walking through all possible disksets */
1974*0Sstevel@tonic-gate 		for (setno = 1; setno < max_sets; setno++) {
1975*0Sstevel@tonic-gate 			if ((sp = metasetnosetname(setno, ep)) == NULL) {
1976*0Sstevel@tonic-gate 				if (mdiserror(ep, MDE_NO_SET)) {
1977*0Sstevel@tonic-gate 					/* No set for this setno - continue */
1978*0Sstevel@tonic-gate 					mdclrerror(ep);
1979*0Sstevel@tonic-gate 					continue;
1980*0Sstevel@tonic-gate 				} else {
1981*0Sstevel@tonic-gate 					(void) sprintf(p, gettext(
1982*0Sstevel@tonic-gate 					    "Unable to get set %d information"),
1983*0Sstevel@tonic-gate 					    setno);
1984*0Sstevel@tonic-gate 					mde_perror(ep, p);
1985*0Sstevel@tonic-gate 					cumm_err = 1;
1986*0Sstevel@tonic-gate 					mdclrerror(ep);
1987*0Sstevel@tonic-gate 					continue;
1988*0Sstevel@tonic-gate 				}
1989*0Sstevel@tonic-gate 			}
1990*0Sstevel@tonic-gate 
1991*0Sstevel@tonic-gate 			/* If setname is there, set desc should exist. */
1992*0Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1993*0Sstevel@tonic-gate 				(void) snprintf(p, bufsz, gettext(
1994*0Sstevel@tonic-gate 				    "Unable to get set %s desc information"),
1995*0Sstevel@tonic-gate 				    sp->setname);
1996*0Sstevel@tonic-gate 				mde_perror(ep, p);
1997*0Sstevel@tonic-gate 				cumm_err = 1;
1998*0Sstevel@tonic-gate 				mdclrerror(ep);
1999*0Sstevel@tonic-gate 				continue;
2000*0Sstevel@tonic-gate 			}
2001*0Sstevel@tonic-gate 
2002*0Sstevel@tonic-gate 			/* Only check MN disksets */
2003*0Sstevel@tonic-gate 			if (!MD_MNSET_DESC(sd)) {
2004*0Sstevel@tonic-gate 				continue;
2005*0Sstevel@tonic-gate 			}
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate 			/*
2008*0Sstevel@tonic-gate 			 * Return value of 0 is success.
2009*0Sstevel@tonic-gate 			 * Return value of -1 means a failure.
2010*0Sstevel@tonic-gate 			 * Return value of -2 means set could not be
2011*0Sstevel@tonic-gate 			 * withdrawn from, but this shouldn't cause
2012*0Sstevel@tonic-gate 			 * an error.  Reasons would be:
2013*0Sstevel@tonic-gate 			 * 	- no drives in set
2014*0Sstevel@tonic-gate 			 * 	- node already withdrawn from set
2015*0Sstevel@tonic-gate 			 * Can't check for all reasons here
2016*0Sstevel@tonic-gate 			 * since set isn't locked yet across all
2017*0Sstevel@tonic-gate 			 * nodes in the cluster.  The call
2018*0Sstevel@tonic-gate 			 * to libmeta routine, meta_set_withdraw, will
2019*0Sstevel@tonic-gate 			 * lock across the cluster and perform
2020*0Sstevel@tonic-gate 			 * the checks.
2021*0Sstevel@tonic-gate 			 */
2022*0Sstevel@tonic-gate 			if ((err = meta_set_withdraw(sp, ep)) == -1) {
2023*0Sstevel@tonic-gate 				/* Print error of diskset withdraw failure */
2024*0Sstevel@tonic-gate 				(void) snprintf(p, bufsz,
2025*0Sstevel@tonic-gate 				    gettext("Withdraw from diskset %s failed"),
2026*0Sstevel@tonic-gate 				    sp->setname);
2027*0Sstevel@tonic-gate 				mde_perror(ep, p);
2028*0Sstevel@tonic-gate 				mdclrerror(ep);
2029*0Sstevel@tonic-gate 				cumm_err = 1;
2030*0Sstevel@tonic-gate 				continue;
2031*0Sstevel@tonic-gate 			}
2032*0Sstevel@tonic-gate 
2033*0Sstevel@tonic-gate 			if (err == -2) {
2034*0Sstevel@tonic-gate 				mdclrerror(ep);
2035*0Sstevel@tonic-gate 				continue;
2036*0Sstevel@tonic-gate 			}
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate 			mdclrerror(ep);
2039*0Sstevel@tonic-gate 		}
2040*0Sstevel@tonic-gate 		md_exit(local_sp, cumm_err);
2041*0Sstevel@tonic-gate 	}
2042*0Sstevel@tonic-gate 
2043*0Sstevel@tonic-gate 
2044*0Sstevel@tonic-gate 	/*
2045*0Sstevel@tonic-gate 	 * Code for a specific set is much simpler.
2046*0Sstevel@tonic-gate 	 * Error messages don't need extra text since specific setname
2047*0Sstevel@tonic-gate 	 * was used.
2048*0Sstevel@tonic-gate 	 * Don't need to lock the local set, just the specific set given.
2049*0Sstevel@tonic-gate 	 */
2050*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
2051*0Sstevel@tonic-gate 		mde_perror(ep, "");
2052*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
2053*0Sstevel@tonic-gate 	}
2054*0Sstevel@tonic-gate 
2055*0Sstevel@tonic-gate 	/*
2056*0Sstevel@tonic-gate 	 * Fail command if meta_set_withdraw returns -1.
2057*0Sstevel@tonic-gate 	 *
2058*0Sstevel@tonic-gate 	 * Return of 0 means that node withdrew from set.
2059*0Sstevel@tonic-gate 	 *
2060*0Sstevel@tonic-gate 	 * Return of -2 means that node was unable to
2061*0Sstevel@tonic-gate 	 * withdraw from a set since that set had no drives
2062*0Sstevel@tonic-gate 	 * or node was not joined to set.  No
2063*0Sstevel@tonic-gate 	 * need to fail the command for these reasons.
2064*0Sstevel@tonic-gate 	 */
2065*0Sstevel@tonic-gate 	if (meta_set_withdraw(sp, ep) == -1) {
2066*0Sstevel@tonic-gate 		mde_perror(&status, "");
2067*0Sstevel@tonic-gate 		md_exit(local_sp, 1);
2068*0Sstevel@tonic-gate 	}
2069*0Sstevel@tonic-gate 
2070*0Sstevel@tonic-gate 	md_exit(local_sp, 0);
2071*0Sstevel@tonic-gate }
2072*0Sstevel@tonic-gate 
2073*0Sstevel@tonic-gate /*
2074*0Sstevel@tonic-gate  * Should never be called with sname of a Multinode diskset.
2075*0Sstevel@tonic-gate  */
2076*0Sstevel@tonic-gate static void
2077*0Sstevel@tonic-gate parse_cluster(int argc, char **argv)
2078*0Sstevel@tonic-gate {
2079*0Sstevel@tonic-gate 	int			c,
2080*0Sstevel@tonic-gate 				error,
2081*0Sstevel@tonic-gate 				new_argc,
2082*0Sstevel@tonic-gate 				x;
2083*0Sstevel@tonic-gate 	enum cluster_cmd	cmd = ccnotspecified;
2084*0Sstevel@tonic-gate 	char			*hostname = SDSSC_PROXY_PRIMARY,
2085*0Sstevel@tonic-gate 				*argument = NULL,
2086*0Sstevel@tonic-gate 				*sname = MD_LOCAL_NAME,
2087*0Sstevel@tonic-gate 				primary_node[SDSSC_NODE_NAME_LEN],
2088*0Sstevel@tonic-gate 				**new_argv = NULL,
2089*0Sstevel@tonic-gate 				**np = NULL;
2090*0Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
2091*0Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
2092*0Sstevel@tonic-gate 	md_error_t		*ep = &status;
2093*0Sstevel@tonic-gate 
2094*0Sstevel@tonic-gate 	/* reset and parse args */
2095*0Sstevel@tonic-gate 	optind = 1;
2096*0Sstevel@tonic-gate 	opterr = 1;
2097*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "C:s:h:fntu:yr")) != -1) {
2098*0Sstevel@tonic-gate 		switch (c) {
2099*0Sstevel@tonic-gate 		case 'C':
2100*0Sstevel@tonic-gate 			if (cmd != ccnotspecified) {
2101*0Sstevel@tonic-gate 				md_exit(sp, -1);
2102*0Sstevel@tonic-gate 			}
2103*0Sstevel@tonic-gate 			argument = optarg;
2104*0Sstevel@tonic-gate 
2105*0Sstevel@tonic-gate 			if (strcmp(argument, "disksin") == 0) {
2106*0Sstevel@tonic-gate 				cmd = clusterdisksin;
2107*0Sstevel@tonic-gate 			} else if (strcmp(argument, "version") == 0) {
2108*0Sstevel@tonic-gate 				cmd = clusterversion;
2109*0Sstevel@tonic-gate 			} else if (strcmp(argument, "release") == 0) {
2110*0Sstevel@tonic-gate 				cmd = clusterrelease;
2111*0Sstevel@tonic-gate 			} else if (strcmp(argument, "take") == 0) {
2112*0Sstevel@tonic-gate 				cmd = clustertake;
2113*0Sstevel@tonic-gate 			} else if (strcmp(argument, "proxy") == 0) {
2114*0Sstevel@tonic-gate 				cmd = clusterproxy;
2115*0Sstevel@tonic-gate 			} else if (strcmp(argument, "purge") == 0) {
2116*0Sstevel@tonic-gate 				cmd = clusterpurge;
2117*0Sstevel@tonic-gate 			} else {
2118*0Sstevel@tonic-gate 				md_exit(sp, -1);
2119*0Sstevel@tonic-gate 			}
2120*0Sstevel@tonic-gate 
2121*0Sstevel@tonic-gate 			break;
2122*0Sstevel@tonic-gate 
2123*0Sstevel@tonic-gate 		case 'h':
2124*0Sstevel@tonic-gate 			hostname = optarg;
2125*0Sstevel@tonic-gate 			break;
2126*0Sstevel@tonic-gate 
2127*0Sstevel@tonic-gate 		case 's':
2128*0Sstevel@tonic-gate 			sname = optarg;
2129*0Sstevel@tonic-gate 			break;
2130*0Sstevel@tonic-gate 
2131*0Sstevel@tonic-gate 		case 'f':
2132*0Sstevel@tonic-gate 		case 'n':
2133*0Sstevel@tonic-gate 		case 't':
2134*0Sstevel@tonic-gate 		case 'u':
2135*0Sstevel@tonic-gate 		case 'y':
2136*0Sstevel@tonic-gate 		case 'r':
2137*0Sstevel@tonic-gate 			break;
2138*0Sstevel@tonic-gate 
2139*0Sstevel@tonic-gate 		default:
2140*0Sstevel@tonic-gate 			md_exit(sp, -1);
2141*0Sstevel@tonic-gate 		}
2142*0Sstevel@tonic-gate 	}
2143*0Sstevel@tonic-gate 
2144*0Sstevel@tonic-gate 	/* Now call the appropriate command function. */
2145*0Sstevel@tonic-gate 	switch (cmd) {
2146*0Sstevel@tonic-gate 	case clusterversion:
2147*0Sstevel@tonic-gate 	    printclusterversion();
2148*0Sstevel@tonic-gate 	    break;
2149*0Sstevel@tonic-gate 
2150*0Sstevel@tonic-gate 	case clusterdisksin:
2151*0Sstevel@tonic-gate 	    if (printdisksin(sname, ep)) {
2152*0Sstevel@tonic-gate 		md_exit(sp, -1);
2153*0Sstevel@tonic-gate 	    }
2154*0Sstevel@tonic-gate 	    break;
2155*0Sstevel@tonic-gate 
2156*0Sstevel@tonic-gate 	case clusterrelease:
2157*0Sstevel@tonic-gate 	    parse_releaseset(argc, argv);
2158*0Sstevel@tonic-gate 	    break;
2159*0Sstevel@tonic-gate 
2160*0Sstevel@tonic-gate 	case clustertake:
2161*0Sstevel@tonic-gate 	    parse_takeset(argc, argv);
2162*0Sstevel@tonic-gate 	    break;
2163*0Sstevel@tonic-gate 
2164*0Sstevel@tonic-gate 	case clusterproxy:
2165*0Sstevel@tonic-gate 		/* Should never get here if sname is for MN diskset */
2166*0Sstevel@tonic-gate 
2167*0Sstevel@tonic-gate 		if ((new_argv = calloc(argc, sizeof (char *))) == NULL) {
2168*0Sstevel@tonic-gate 			printf(gettext("Out of memory\n"));
2169*0Sstevel@tonic-gate 			md_exit(sp, 1);
2170*0Sstevel@tonic-gate 		}
2171*0Sstevel@tonic-gate 
2172*0Sstevel@tonic-gate 		np = new_argv;
2173*0Sstevel@tonic-gate 		new_argc = 0;
2174*0Sstevel@tonic-gate 		memset(primary_node, '\0', SDSSC_NODE_NAME_LEN);
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 		for (x = 0; x < argc; x++) {
2177*0Sstevel@tonic-gate 			if (strcmp(argv[x], "-C") == 0) {
2178*0Sstevel@tonic-gate 
2179*0Sstevel@tonic-gate 				/*
2180*0Sstevel@tonic-gate 				 * Need to skip the '-C proxy' args so
2181*0Sstevel@tonic-gate 				 * just increase x by one and the work is
2182*0Sstevel@tonic-gate 				 * done.
2183*0Sstevel@tonic-gate 				 */
2184*0Sstevel@tonic-gate 				x++;
2185*0Sstevel@tonic-gate 			} else {
2186*0Sstevel@tonic-gate 				*np++ = strdup(argv[x]);
2187*0Sstevel@tonic-gate 				new_argc++;
2188*0Sstevel@tonic-gate 			}
2189*0Sstevel@tonic-gate 		}
2190*0Sstevel@tonic-gate 
2191*0Sstevel@tonic-gate 		switch (sdssc_get_primary_host(sname, primary_node,
2192*0Sstevel@tonic-gate 		    SDSSC_NODE_NAME_LEN)) {
2193*0Sstevel@tonic-gate 		case SDSSC_ERROR:
2194*0Sstevel@tonic-gate 			md_exit(sp, 1);
2195*0Sstevel@tonic-gate 			break;
2196*0Sstevel@tonic-gate 
2197*0Sstevel@tonic-gate 		case SDSSC_NO_SERVICE:
2198*0Sstevel@tonic-gate 			if (hostname != SDSSC_PROXY_PRIMARY) {
2199*0Sstevel@tonic-gate 				(void) strlcpy(primary_node, hostname,
2200*0Sstevel@tonic-gate 				    SDSSC_NODE_NAME_LEN);
2201*0Sstevel@tonic-gate 			}
2202*0Sstevel@tonic-gate 			break;
2203*0Sstevel@tonic-gate 		}
2204*0Sstevel@tonic-gate 
2205*0Sstevel@tonic-gate 		if (sdssc_cmd_proxy(new_argc, new_argv,
2206*0Sstevel@tonic-gate 		    primary_node[0] == '\0' ? SDSSC_PROXY_PRIMARY :
2207*0Sstevel@tonic-gate 		    primary_node, &error) == SDSSC_PROXY_DONE) {
2208*0Sstevel@tonic-gate 			md_exit(sp, error);
2209*0Sstevel@tonic-gate 		} else {
2210*0Sstevel@tonic-gate 			printf(gettext(
2211*0Sstevel@tonic-gate 			    "Couldn't proxy command\n"));
2212*0Sstevel@tonic-gate 			md_exit(sp, 1);
2213*0Sstevel@tonic-gate 		}
2214*0Sstevel@tonic-gate 		break;
2215*0Sstevel@tonic-gate 
2216*0Sstevel@tonic-gate 	case clusterpurge:
2217*0Sstevel@tonic-gate 		parse_purge(argc, argv);
2218*0Sstevel@tonic-gate 		break;
2219*0Sstevel@tonic-gate 
2220*0Sstevel@tonic-gate 	default:
2221*0Sstevel@tonic-gate 	    break;
2222*0Sstevel@tonic-gate 	}
2223*0Sstevel@tonic-gate 
2224*0Sstevel@tonic-gate 	md_exit(sp, 0);
2225*0Sstevel@tonic-gate }
2226*0Sstevel@tonic-gate 
2227*0Sstevel@tonic-gate /*
2228*0Sstevel@tonic-gate  * parse args and do it
2229*0Sstevel@tonic-gate  */
2230*0Sstevel@tonic-gate int
2231*0Sstevel@tonic-gate main(int argc, char *argv[])
2232*0Sstevel@tonic-gate {
2233*0Sstevel@tonic-gate 	enum metaset_cmd	cmd = notspecified;
2234*0Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
2235*0Sstevel@tonic-gate 	md_error_t		*ep = &status;
2236*0Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
2237*0Sstevel@tonic-gate 	char			*hostname = SDSSC_PROXY_PRIMARY,
2238*0Sstevel@tonic-gate 				*sname = MD_LOCAL_NAME,
2239*0Sstevel@tonic-gate 				*auto_take_option = NULL,
2240*0Sstevel@tonic-gate 				primary_node[SDSSC_NODE_NAME_LEN];
2241*0Sstevel@tonic-gate 	int			error,
2242*0Sstevel@tonic-gate 				c,
2243*0Sstevel@tonic-gate 				auto_take = FALSE,
2244*0Sstevel@tonic-gate 				stat;
2245*0Sstevel@tonic-gate 	md_set_desc		*sd;
2246*0Sstevel@tonic-gate 	int			mflag = 0;
2247*0Sstevel@tonic-gate 	int			multi_node = 0;
2248*0Sstevel@tonic-gate 	rval_e			sdssc_res;
2249*0Sstevel@tonic-gate 
2250*0Sstevel@tonic-gate 	/*
2251*0Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
2252*0Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
2253*0Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
2254*0Sstevel@tonic-gate 	 * something.
2255*0Sstevel@tonic-gate 	 */
2256*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2257*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
2258*0Sstevel@tonic-gate #endif
2259*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2260*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2261*0Sstevel@tonic-gate 
2262*0Sstevel@tonic-gate 	sdssc_res = sdssc_bind_library();
2263*0Sstevel@tonic-gate 	if (sdssc_res == SDSSC_ERROR) {
2264*0Sstevel@tonic-gate 		printf(gettext(
2265*0Sstevel@tonic-gate 		    "%s: Interface error with libsds_sc.so\n"), argv[0]);
2266*0Sstevel@tonic-gate 		exit(1);
2267*0Sstevel@tonic-gate 	}
2268*0Sstevel@tonic-gate 
2269*0Sstevel@tonic-gate 	/* initialize */
2270*0Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
2271*0Sstevel@tonic-gate 		mde_perror(ep, "");
2272*0Sstevel@tonic-gate 		md_exit(sp, 1);
2273*0Sstevel@tonic-gate 	}
2274*0Sstevel@tonic-gate 
2275*0Sstevel@tonic-gate 	optind = 1;
2276*0Sstevel@tonic-gate 	opterr = 1;
2277*0Sstevel@tonic-gate 
2278*0Sstevel@tonic-gate 	/*
2279*0Sstevel@tonic-gate 	 * NOTE: The "C" option is strictly for cluster use. it is not
2280*0Sstevel@tonic-gate 	 * and should not be documented for the customer. - JST
2281*0Sstevel@tonic-gate 	 */
2282*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "C:MaA:bdfh:jl:Lm:noPqrs:tu:wy?"))
2283*0Sstevel@tonic-gate 	    != -1) {
2284*0Sstevel@tonic-gate 		switch (c) {
2285*0Sstevel@tonic-gate 		case 'M':
2286*0Sstevel@tonic-gate 			mflag = 1;
2287*0Sstevel@tonic-gate 			break;
2288*0Sstevel@tonic-gate 		case 'A':
2289*0Sstevel@tonic-gate 			auto_take = TRUE;
2290*0Sstevel@tonic-gate 			if (optarg == NULL || !(strcmp(optarg, "enable") == 0 ||
2291*0Sstevel@tonic-gate 			    strcmp(optarg, "disable") == 0))
2292*0Sstevel@tonic-gate 				usage(sp, gettext(
2293*0Sstevel@tonic-gate 				    "-A: enable or disable must be specified"));
2294*0Sstevel@tonic-gate 			auto_take_option = optarg;
2295*0Sstevel@tonic-gate 			break;
2296*0Sstevel@tonic-gate 		case 'a':
2297*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2298*0Sstevel@tonic-gate 				usage(sp, gettext(
2299*0Sstevel@tonic-gate 				    "conflicting options"));
2300*0Sstevel@tonic-gate 			}
2301*0Sstevel@tonic-gate 			cmd = add;
2302*0Sstevel@tonic-gate 			break;
2303*0Sstevel@tonic-gate 		case 'b':
2304*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2305*0Sstevel@tonic-gate 				usage(sp, gettext(
2306*0Sstevel@tonic-gate 				    "conflicting options"));
2307*0Sstevel@tonic-gate 			}
2308*0Sstevel@tonic-gate 			cmd = balance;
2309*0Sstevel@tonic-gate 			break;
2310*0Sstevel@tonic-gate 		case 'd':
2311*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2312*0Sstevel@tonic-gate 				usage(sp, gettext(
2313*0Sstevel@tonic-gate 				    "conflicting options"));
2314*0Sstevel@tonic-gate 			}
2315*0Sstevel@tonic-gate 			cmd = delete;
2316*0Sstevel@tonic-gate 			break;
2317*0Sstevel@tonic-gate 		case 'C':	/* cluster commands */
2318*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2319*0Sstevel@tonic-gate 				md_exit(sp, -1);    /* conflicting options */
2320*0Sstevel@tonic-gate 			}
2321*0Sstevel@tonic-gate 			cmd = cluster;
2322*0Sstevel@tonic-gate 			break;
2323*0Sstevel@tonic-gate 		case 'f':
2324*0Sstevel@tonic-gate 			break;
2325*0Sstevel@tonic-gate 		case 'h':
2326*0Sstevel@tonic-gate 			hostname = optarg;
2327*0Sstevel@tonic-gate 			break;
2328*0Sstevel@tonic-gate 		case 'j':
2329*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2330*0Sstevel@tonic-gate 				usage(sp, gettext(
2331*0Sstevel@tonic-gate 				    "conflicting options"));
2332*0Sstevel@tonic-gate 			}
2333*0Sstevel@tonic-gate 			cmd = join;
2334*0Sstevel@tonic-gate 			break;
2335*0Sstevel@tonic-gate 		case 'l':
2336*0Sstevel@tonic-gate 			break;
2337*0Sstevel@tonic-gate 		case 'L':
2338*0Sstevel@tonic-gate 			break;
2339*0Sstevel@tonic-gate 		case 'm':
2340*0Sstevel@tonic-gate 			break;
2341*0Sstevel@tonic-gate 		case 'n':
2342*0Sstevel@tonic-gate 			break;
2343*0Sstevel@tonic-gate 		case 'o':
2344*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2345*0Sstevel@tonic-gate 				usage(sp, gettext(
2346*0Sstevel@tonic-gate 				    "conflicting options"));
2347*0Sstevel@tonic-gate 			}
2348*0Sstevel@tonic-gate 			cmd = isowner;
2349*0Sstevel@tonic-gate 			break;
2350*0Sstevel@tonic-gate 		case 'P':
2351*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2352*0Sstevel@tonic-gate 				usage(sp, gettext(
2353*0Sstevel@tonic-gate 				    "conflicting options"));
2354*0Sstevel@tonic-gate 			}
2355*0Sstevel@tonic-gate 			cmd = purge;
2356*0Sstevel@tonic-gate 			break;
2357*0Sstevel@tonic-gate 		case 'q':
2358*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2359*0Sstevel@tonic-gate 				usage(sp, gettext(
2360*0Sstevel@tonic-gate 				    "conflicting options"));
2361*0Sstevel@tonic-gate 			}
2362*0Sstevel@tonic-gate 			cmd = query;
2363*0Sstevel@tonic-gate 			break;
2364*0Sstevel@tonic-gate 		case 'r':
2365*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2366*0Sstevel@tonic-gate 				usage(sp, gettext(
2367*0Sstevel@tonic-gate 				    "conflicting options"));
2368*0Sstevel@tonic-gate 			}
2369*0Sstevel@tonic-gate 			cmd = release;
2370*0Sstevel@tonic-gate 			break;
2371*0Sstevel@tonic-gate 		case 's':
2372*0Sstevel@tonic-gate 			sname = optarg;
2373*0Sstevel@tonic-gate 			break;
2374*0Sstevel@tonic-gate 		case 't':
2375*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2376*0Sstevel@tonic-gate 				usage(sp, gettext(
2377*0Sstevel@tonic-gate 				    "conflicting options"));
2378*0Sstevel@tonic-gate 			}
2379*0Sstevel@tonic-gate 			cmd = take;
2380*0Sstevel@tonic-gate 			break;
2381*0Sstevel@tonic-gate 		case 'u':
2382*0Sstevel@tonic-gate 			break;
2383*0Sstevel@tonic-gate 		case 'w':
2384*0Sstevel@tonic-gate 			if (cmd != notspecified) {
2385*0Sstevel@tonic-gate 				usage(sp, gettext(
2386*0Sstevel@tonic-gate 				    "conflicting options"));
2387*0Sstevel@tonic-gate 			}
2388*0Sstevel@tonic-gate 			cmd = withdraw;
2389*0Sstevel@tonic-gate 			break;
2390*0Sstevel@tonic-gate 		case 'y':
2391*0Sstevel@tonic-gate 			break;
2392*0Sstevel@tonic-gate 		case '?':
2393*0Sstevel@tonic-gate 			if (optopt == '?')
2394*0Sstevel@tonic-gate 				usage(sp, NULL);
2395*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
2396*0Sstevel@tonic-gate 		default:
2397*0Sstevel@tonic-gate 			if (cmd == cluster) {    /* cluster is silent */
2398*0Sstevel@tonic-gate 				md_exit(sp, -1);
2399*0Sstevel@tonic-gate 			} else {
2400*0Sstevel@tonic-gate 				usage(sp, gettext(
2401*0Sstevel@tonic-gate 				    "unknown command"));
2402*0Sstevel@tonic-gate 			}
2403*0Sstevel@tonic-gate 		}
2404*0Sstevel@tonic-gate 	}
2405*0Sstevel@tonic-gate 
2406*0Sstevel@tonic-gate 	/* check if suncluster is installed and -A enable specified */
2407*0Sstevel@tonic-gate 	if (auto_take && sdssc_res != SDSSC_NOT_BOUND &&
2408*0Sstevel@tonic-gate 	    strcmp(auto_take_option, "enable") == 0) {
2409*0Sstevel@tonic-gate 	    md_eprintf(gettext(
2410*0Sstevel@tonic-gate 		"cannot enable auto-take when SunCluster is installed\n"));
2411*0Sstevel@tonic-gate 	    md_exit(sp, 1);
2412*0Sstevel@tonic-gate 	}
2413*0Sstevel@tonic-gate 
2414*0Sstevel@tonic-gate 	/*
2415*0Sstevel@tonic-gate 	 * At this point we know that if the -A enable option is specified
2416*0Sstevel@tonic-gate 	 * for an auto-take diskset that SC is not installed on the machine, so
2417*0Sstevel@tonic-gate 	 * all of the sdssc calls will just be no-ops.
2418*0Sstevel@tonic-gate 	 */
2419*0Sstevel@tonic-gate 
2420*0Sstevel@tonic-gate 	/* list sets */
2421*0Sstevel@tonic-gate 	if (cmd == notspecified && auto_take == FALSE) {
2422*0Sstevel@tonic-gate 		parse_printset(argc, argv);
2423*0Sstevel@tonic-gate 		/*NOTREACHED*/
2424*0Sstevel@tonic-gate 	}
2425*0Sstevel@tonic-gate 
2426*0Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
2427*0Sstevel@tonic-gate 		mde_perror(ep, "");
2428*0Sstevel@tonic-gate 		md_exit(sp, 1);
2429*0Sstevel@tonic-gate 	}
2430*0Sstevel@tonic-gate 
2431*0Sstevel@tonic-gate 	/* snarf MDDB */
2432*0Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
2433*0Sstevel@tonic-gate 		mde_perror(ep, "");
2434*0Sstevel@tonic-gate 		md_exit(sp, 1);
2435*0Sstevel@tonic-gate 	}
2436*0Sstevel@tonic-gate 
2437*0Sstevel@tonic-gate 	/*
2438*0Sstevel@tonic-gate 	 * If sname is a diskset - check for multi_node.
2439*0Sstevel@tonic-gate 	 * It is possible for sname to not exist.
2440*0Sstevel@tonic-gate 	 */
2441*0Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME)) {
2442*0Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) != NULL) {
2443*0Sstevel@tonic-gate 			/* Set exists - check for MN diskset */
2444*0Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
2445*0Sstevel@tonic-gate 				mde_perror(ep, "");
2446*0Sstevel@tonic-gate 				md_exit(sp, 1);
2447*0Sstevel@tonic-gate 			}
2448*0Sstevel@tonic-gate 			if (MD_MNSET_DESC(sd)) {
2449*0Sstevel@tonic-gate 				/*
2450*0Sstevel@tonic-gate 				 * If a MN diskset always set multi_node
2451*0Sstevel@tonic-gate 				 * regardless of whether the -M option was
2452*0Sstevel@tonic-gate 				 * used or not (mflag).
2453*0Sstevel@tonic-gate 				 */
2454*0Sstevel@tonic-gate 				multi_node = 1;
2455*0Sstevel@tonic-gate 			} else {
2456*0Sstevel@tonic-gate 				/*
2457*0Sstevel@tonic-gate 				 * If a traditional diskset, mflag must
2458*0Sstevel@tonic-gate 				 * not be set.
2459*0Sstevel@tonic-gate 				 */
2460*0Sstevel@tonic-gate 				if (mflag) {
2461*0Sstevel@tonic-gate 					usage(sp, gettext(
2462*0Sstevel@tonic-gate 					    "-M option only allowed "
2463*0Sstevel@tonic-gate 					    "on multi-owner diskset"));
2464*0Sstevel@tonic-gate 				}
2465*0Sstevel@tonic-gate 			}
2466*0Sstevel@tonic-gate 		} else {
2467*0Sstevel@tonic-gate 			/*
2468*0Sstevel@tonic-gate 			 * Set name does not exist, set multi_node
2469*0Sstevel@tonic-gate 			 * based on -M option.
2470*0Sstevel@tonic-gate 			 */
2471*0Sstevel@tonic-gate 			if (mflag) {
2472*0Sstevel@tonic-gate 				multi_node = 1;
2473*0Sstevel@tonic-gate 			}
2474*0Sstevel@tonic-gate 		}
2475*0Sstevel@tonic-gate 	}
2476*0Sstevel@tonic-gate 
2477*0Sstevel@tonic-gate 	if (auto_take && multi_node) {
2478*0Sstevel@tonic-gate 		/* Can't mix multinode and auto-take on a diskset */
2479*0Sstevel@tonic-gate 		usage(sp,
2480*0Sstevel@tonic-gate 		    gettext("-A option not allowed on multi-owner diskset"));
2481*0Sstevel@tonic-gate 	}
2482*0Sstevel@tonic-gate 
2483*0Sstevel@tonic-gate 	/*
2484*0Sstevel@tonic-gate 	 * MN disksets don't use DCS clustering services, so
2485*0Sstevel@tonic-gate 	 * do not get primary_node for MN diskset since no command
2486*0Sstevel@tonic-gate 	 * proxying is done to Primary cluster node.  Do not proxy
2487*0Sstevel@tonic-gate 	 * MN diskset commands of join and withdraw when issued without
2488*0Sstevel@tonic-gate 	 * a valid setname.
2489*0Sstevel@tonic-gate 	 * For traditional disksets: proxy all commands except a take
2490*0Sstevel@tonic-gate 	 * and release.  Use first host listed as the host to send the
2491*0Sstevel@tonic-gate 	 * command to if there isn't already a primary
2492*0Sstevel@tonic-gate 	 */
2493*0Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) && (multi_node == 0) &&
2494*0Sstevel@tonic-gate 	    (cmd != take) && (cmd != release) &&
2495*0Sstevel@tonic-gate 	    (cmd != cluster) && (cmd != join) &&
2496*0Sstevel@tonic-gate 	    (cmd != withdraw) && (cmd != purge)) {
2497*0Sstevel@tonic-gate 		stat = sdssc_get_primary_host(sname, primary_node,
2498*0Sstevel@tonic-gate 		    SDSSC_NODE_NAME_LEN);
2499*0Sstevel@tonic-gate 		switch (stat) {
2500*0Sstevel@tonic-gate 			case SDSSC_ERROR:
2501*0Sstevel@tonic-gate 				return (0);
2502*0Sstevel@tonic-gate 
2503*0Sstevel@tonic-gate 			case SDSSC_NO_SERVICE:
2504*0Sstevel@tonic-gate 				if (hostname != SDSSC_PROXY_PRIMARY) {
2505*0Sstevel@tonic-gate 					(void) strlcpy(primary_node, hostname,
2506*0Sstevel@tonic-gate 					    SDSSC_NODE_NAME_LEN);
2507*0Sstevel@tonic-gate 				} else {
2508*0Sstevel@tonic-gate 					memset(primary_node, '\0',
2509*0Sstevel@tonic-gate 					    SDSSC_NODE_NAME_LEN);
2510*0Sstevel@tonic-gate 				}
2511*0Sstevel@tonic-gate 				break;
2512*0Sstevel@tonic-gate 		}
2513*0Sstevel@tonic-gate 
2514*0Sstevel@tonic-gate 		/*
2515*0Sstevel@tonic-gate 		 * We've got a complicated decision here regarding
2516*0Sstevel@tonic-gate 		 * the hostname. If we didn't get a primary host
2517*0Sstevel@tonic-gate 		 * and a host name wasn't supplied on the command line
2518*0Sstevel@tonic-gate 		 * then we need to revert to SDSSC_PROXY_PRIMARY. Otherwise
2519*0Sstevel@tonic-gate 		 * use what's been found.
2520*0Sstevel@tonic-gate 		 */
2521*0Sstevel@tonic-gate 		if (sdssc_cmd_proxy(argc, argv,
2522*0Sstevel@tonic-gate 		    primary_node[0] == '\0' ?
2523*0Sstevel@tonic-gate 			SDSSC_PROXY_PRIMARY : primary_node,
2524*0Sstevel@tonic-gate 		    &error) == SDSSC_PROXY_DONE) {
2525*0Sstevel@tonic-gate 			exit(error);
2526*0Sstevel@tonic-gate 		}
2527*0Sstevel@tonic-gate 	}
2528*0Sstevel@tonic-gate 
2529*0Sstevel@tonic-gate 	/* cluster-specific commands */
2530*0Sstevel@tonic-gate 	if (cmd == cluster) {
2531*0Sstevel@tonic-gate 		if (multi_node) {
2532*0Sstevel@tonic-gate 			/*
2533*0Sstevel@tonic-gate 			 * If a specific MN diskset is given, immediately
2534*0Sstevel@tonic-gate 			 * fail -C command.
2535*0Sstevel@tonic-gate 			 */
2536*0Sstevel@tonic-gate 			usage(sp, gettext(
2537*0Sstevel@tonic-gate 			    "-C option not allowed on multi-owner diskset"));
2538*0Sstevel@tonic-gate 		} else {
2539*0Sstevel@tonic-gate 			parse_cluster(argc, argv);
2540*0Sstevel@tonic-gate 			/*NOTREACHED*/
2541*0Sstevel@tonic-gate 		}
2542*0Sstevel@tonic-gate 	}
2543*0Sstevel@tonic-gate 
2544*0Sstevel@tonic-gate 	/* join MultiNode diskset */
2545*0Sstevel@tonic-gate 	if (cmd == join) {
2546*0Sstevel@tonic-gate 		/*
2547*0Sstevel@tonic-gate 		 * If diskset specified, verify that it exists
2548*0Sstevel@tonic-gate 		 * and is a multinode diskset.
2549*0Sstevel@tonic-gate 		 */
2550*0Sstevel@tonic-gate 		if (strcmp(sname, MD_LOCAL_NAME)) {
2551*0Sstevel@tonic-gate 			if ((sp = metasetname(sname, ep)) == NULL) {
2552*0Sstevel@tonic-gate 				mde_perror(ep, "");
2553*0Sstevel@tonic-gate 				md_exit(sp, 1);
2554*0Sstevel@tonic-gate 			}
2555*0Sstevel@tonic-gate 
2556*0Sstevel@tonic-gate 			if (!multi_node) {
2557*0Sstevel@tonic-gate 				usage(sp, gettext(
2558*0Sstevel@tonic-gate 				    "-j option only allowed on "
2559*0Sstevel@tonic-gate 				    "multi-owner diskset"));
2560*0Sstevel@tonic-gate 			}
2561*0Sstevel@tonic-gate 		}
2562*0Sstevel@tonic-gate 		/*
2563*0Sstevel@tonic-gate 		 * Start mddoors daemon here.
2564*0Sstevel@tonic-gate 		 * mddoors itself takes care there will be only one
2565*0Sstevel@tonic-gate 		 * instance running, so starting it twice won't hurt
2566*0Sstevel@tonic-gate 		 */
2567*0Sstevel@tonic-gate 		pclose(popen("/usr/lib/lvm/mddoors", "w"));
2568*0Sstevel@tonic-gate 		parse_joinset(argc, argv);
2569*0Sstevel@tonic-gate 		/*NOTREACHED*/
2570*0Sstevel@tonic-gate 	}
2571*0Sstevel@tonic-gate 
2572*0Sstevel@tonic-gate 	/* withdraw from MultiNode diskset */
2573*0Sstevel@tonic-gate 	if (cmd == withdraw) {
2574*0Sstevel@tonic-gate 		/*
2575*0Sstevel@tonic-gate 		 * If diskset specified, verify that it exists
2576*0Sstevel@tonic-gate 		 * and is a multinode diskset.
2577*0Sstevel@tonic-gate 		 */
2578*0Sstevel@tonic-gate 		if (strcmp(sname, MD_LOCAL_NAME)) {
2579*0Sstevel@tonic-gate 			if ((sp = metasetname(sname, ep)) == NULL) {
2580*0Sstevel@tonic-gate 				mde_perror(ep, "");
2581*0Sstevel@tonic-gate 				md_exit(sp, 1);
2582*0Sstevel@tonic-gate 			}
2583*0Sstevel@tonic-gate 
2584*0Sstevel@tonic-gate 			if (!multi_node) {
2585*0Sstevel@tonic-gate 				usage(sp, gettext(
2586*0Sstevel@tonic-gate 				    "-w option only allowed on "
2587*0Sstevel@tonic-gate 				    "multi-owner diskset"));
2588*0Sstevel@tonic-gate 			}
2589*0Sstevel@tonic-gate 		}
2590*0Sstevel@tonic-gate 		parse_withdrawset(argc, argv);
2591*0Sstevel@tonic-gate 		/*NOTREACHED*/
2592*0Sstevel@tonic-gate 	}
2593*0Sstevel@tonic-gate 
2594*0Sstevel@tonic-gate 	/* must have set for everything else */
2595*0Sstevel@tonic-gate 	if (strcmp(sname, MD_LOCAL_NAME) == 0)
2596*0Sstevel@tonic-gate 		usage(sp, gettext("setname must be specified"));
2597*0Sstevel@tonic-gate 
2598*0Sstevel@tonic-gate 	/* add hosts or drives */
2599*0Sstevel@tonic-gate 	if (cmd == add) {
2600*0Sstevel@tonic-gate 		/*
2601*0Sstevel@tonic-gate 		 * In the multi node case start mddoors daemon.
2602*0Sstevel@tonic-gate 		 * mddoors itself takes care there will be
2603*0Sstevel@tonic-gate 		 * only one instance running, so starting it twice won't hurt
2604*0Sstevel@tonic-gate 		 */
2605*0Sstevel@tonic-gate 		if (multi_node) {
2606*0Sstevel@tonic-gate 			pclose(popen("/usr/lib/lvm/mddoors", "w"));
2607*0Sstevel@tonic-gate 		}
2608*0Sstevel@tonic-gate 
2609*0Sstevel@tonic-gate 		parse_add(argc, argv);
2610*0Sstevel@tonic-gate 		/*NOTREACHED*/
2611*0Sstevel@tonic-gate 	}
2612*0Sstevel@tonic-gate 
2613*0Sstevel@tonic-gate 	/* re-balance the replicas */
2614*0Sstevel@tonic-gate 	if (cmd == balance) {
2615*0Sstevel@tonic-gate 		parse_balance(argc, argv);
2616*0Sstevel@tonic-gate 		/*NOTREACHED*/
2617*0Sstevel@tonic-gate 	}
2618*0Sstevel@tonic-gate 
2619*0Sstevel@tonic-gate 	/* delete hosts or drives */
2620*0Sstevel@tonic-gate 	if (cmd == delete) {
2621*0Sstevel@tonic-gate 		parse_del(argc, argv);
2622*0Sstevel@tonic-gate 		/*NOTREACHED*/
2623*0Sstevel@tonic-gate 	}
2624*0Sstevel@tonic-gate 
2625*0Sstevel@tonic-gate 	/* check ownership */
2626*0Sstevel@tonic-gate 	if (cmd == isowner) {
2627*0Sstevel@tonic-gate 		parse_isowner(argc, argv);
2628*0Sstevel@tonic-gate 		/*NOTREACHED*/
2629*0Sstevel@tonic-gate 	}
2630*0Sstevel@tonic-gate 
2631*0Sstevel@tonic-gate 	/* purge the diskset */
2632*0Sstevel@tonic-gate 	if (cmd == purge) {
2633*0Sstevel@tonic-gate 		parse_purge(argc, argv);
2634*0Sstevel@tonic-gate 		/*NOTREACHED*/
2635*0Sstevel@tonic-gate 	}
2636*0Sstevel@tonic-gate 
2637*0Sstevel@tonic-gate 	/* query for data marks */
2638*0Sstevel@tonic-gate 	if (cmd == query) {
2639*0Sstevel@tonic-gate 		parse_query(argc, argv);
2640*0Sstevel@tonic-gate 		/*NOTREACHED*/
2641*0Sstevel@tonic-gate 	}
2642*0Sstevel@tonic-gate 
2643*0Sstevel@tonic-gate 	/* release ownership */
2644*0Sstevel@tonic-gate 	if (cmd == release) {
2645*0Sstevel@tonic-gate 		if (multi_node) {
2646*0Sstevel@tonic-gate 			/* Can't release multinode diskset */
2647*0Sstevel@tonic-gate 			usage(sp, gettext(
2648*0Sstevel@tonic-gate 			    "-r option not allowed on multi-owner diskset"));
2649*0Sstevel@tonic-gate 		} else {
2650*0Sstevel@tonic-gate 			parse_releaseset(argc, argv);
2651*0Sstevel@tonic-gate 			/*NOTREACHED*/
2652*0Sstevel@tonic-gate 		}
2653*0Sstevel@tonic-gate 	}
2654*0Sstevel@tonic-gate 
2655*0Sstevel@tonic-gate 	/* take ownership */
2656*0Sstevel@tonic-gate 	if (cmd == take) {
2657*0Sstevel@tonic-gate 		if (multi_node) {
2658*0Sstevel@tonic-gate 			/* Can't take multinode diskset */
2659*0Sstevel@tonic-gate 			usage(sp, gettext(
2660*0Sstevel@tonic-gate 			    "-t option not allowed on multi-owner diskset"));
2661*0Sstevel@tonic-gate 		} else {
2662*0Sstevel@tonic-gate 			parse_takeset(argc, argv);
2663*0Sstevel@tonic-gate 			/*NOTREACHED*/
2664*0Sstevel@tonic-gate 		}
2665*0Sstevel@tonic-gate 	}
2666*0Sstevel@tonic-gate 
2667*0Sstevel@tonic-gate 	/* take ownership of auto-take sets */
2668*0Sstevel@tonic-gate 	if (auto_take) {
2669*0Sstevel@tonic-gate 		parse_autotake(argc, argv);
2670*0Sstevel@tonic-gate 		/*NOTREACHED*/
2671*0Sstevel@tonic-gate 	}
2672*0Sstevel@tonic-gate 
2673*0Sstevel@tonic-gate 	/*NOTREACHED*/
2674*0Sstevel@tonic-gate 	return (0);
2675*0Sstevel@tonic-gate }
2676