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 2004 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  * hotspare maintenance
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <meta.h>
34*0Sstevel@tonic-gate #include <sdssc.h>
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate /*
37*0Sstevel@tonic-gate  * possible actions
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate enum metahs_op {
40*0Sstevel@tonic-gate 	NONE,
41*0Sstevel@tonic-gate 	ADD_A_HS,
42*0Sstevel@tonic-gate 	DELETE_A_HS,
43*0Sstevel@tonic-gate 	ENABLE_A_HS,
44*0Sstevel@tonic-gate 	REPLACE_A_HS,
45*0Sstevel@tonic-gate 	STATUS_A_HSP
46*0Sstevel@tonic-gate };
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /*
49*0Sstevel@tonic-gate  * report status of a hotspare pool
50*0Sstevel@tonic-gate  */
51*0Sstevel@tonic-gate static int
52*0Sstevel@tonic-gate status_hsp(
53*0Sstevel@tonic-gate 	mdsetname_t	*sp,
54*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
55*0Sstevel@tonic-gate 	md_error_t	*ep
56*0Sstevel@tonic-gate )
57*0Sstevel@tonic-gate {
58*0Sstevel@tonic-gate 	mdprtopts_t	options = (PRINT_HEADER | PRINT_SUBDEVS | PRINT_DEVID);
59*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	/* must have set */
62*0Sstevel@tonic-gate 	assert(sp != NULL);
63*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	/* print status */
66*0Sstevel@tonic-gate 	if (meta_hsp_print(sp, hspnp, &nlp, NULL, stdout, options, ep) != 0)
67*0Sstevel@tonic-gate 		return (-1);
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate 	/* return success */
70*0Sstevel@tonic-gate 	return (0);
71*0Sstevel@tonic-gate }
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate /*
74*0Sstevel@tonic-gate  * print usage message
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate static void
77*0Sstevel@tonic-gate usage(
78*0Sstevel@tonic-gate 	mdsetname_t	*sp,
79*0Sstevel@tonic-gate 	int		eval
80*0Sstevel@tonic-gate )
81*0Sstevel@tonic-gate {
82*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\
83*0Sstevel@tonic-gate usage:	%s [-s setname] -a hot_spare_pool [component...]\n\
84*0Sstevel@tonic-gate 	%s [-s setname] -a \"all\" component...\n\
85*0Sstevel@tonic-gate 	%s [-s setname] -d hot_spare_pool [component...]\n\
86*0Sstevel@tonic-gate 	%s [-s setname] -d \"all\" component...\n\
87*0Sstevel@tonic-gate 	%s [-s setname] -e component...\n\
88*0Sstevel@tonic-gate 	%s [-s setname] -r hot_spare_pool component_old component_new\n\
89*0Sstevel@tonic-gate 	%s [-s setname] -r \"all\" component_old component_new\n\
90*0Sstevel@tonic-gate 	%s [-s setname] -i [hot_spare_pool...]\n"),
91*0Sstevel@tonic-gate 	    myname, myname, myname, myname, myname, myname, myname, myname);
92*0Sstevel@tonic-gate 	md_exit(sp, eval);
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * check for "all"
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate static int
99*0Sstevel@tonic-gate is_all(char *s)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate 	if ((strcoll(s, gettext("all")) == 0) ||
102*0Sstevel@tonic-gate 	    (strcoll(s, gettext("ALL")) == 0))
103*0Sstevel@tonic-gate 		return (1);
104*0Sstevel@tonic-gate 	return (0);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * parse args and add hotspares
109*0Sstevel@tonic-gate  */
110*0Sstevel@tonic-gate static int
111*0Sstevel@tonic-gate add_hotspares(
112*0Sstevel@tonic-gate 	mdsetname_t	**spp,
113*0Sstevel@tonic-gate 	int		argc,
114*0Sstevel@tonic-gate 	char		*argv[],
115*0Sstevel@tonic-gate 	mdcmdopts_t	options,
116*0Sstevel@tonic-gate 	md_error_t	*ep
117*0Sstevel@tonic-gate )
118*0Sstevel@tonic-gate {
119*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
120*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
121*0Sstevel@tonic-gate 	int		cnt;
122*0Sstevel@tonic-gate 	mdhspnamelist_t	*p;
123*0Sstevel@tonic-gate 	int		rval = -1;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	/* get hotspare pool name(s) */
126*0Sstevel@tonic-gate 	if (argc < 1)
127*0Sstevel@tonic-gate 		usage(*spp, 1);
128*0Sstevel@tonic-gate 	if ((argc > 1) && is_all(argv[0])) {
129*0Sstevel@tonic-gate 		if ((*spp == NULL) &&
130*0Sstevel@tonic-gate 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
131*0Sstevel@tonic-gate 			return (-1);
132*0Sstevel@tonic-gate 		}
133*0Sstevel@tonic-gate 		/* check for ownership */
134*0Sstevel@tonic-gate 		assert(*spp != NULL);
135*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
136*0Sstevel@tonic-gate 			return (-1);
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
139*0Sstevel@tonic-gate 			return (-1);
140*0Sstevel@tonic-gate 		} else if (cnt == 0) {
141*0Sstevel@tonic-gate 			return (mderror(ep, MDE_NO_HSPS, NULL));
142*0Sstevel@tonic-gate 		}
143*0Sstevel@tonic-gate 	} else if ((cnt = metahspnamelist(spp, &hspnlp, 1, &argv[0],
144*0Sstevel@tonic-gate 	    ep)) < 0) {
145*0Sstevel@tonic-gate 		return (-1);
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate 	assert(cnt > 0);
148*0Sstevel@tonic-gate 	--argc, ++argv;
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	assert(*spp != NULL);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	/* grab set lock */
153*0Sstevel@tonic-gate 	if (meta_lock(*spp, TRUE, ep))
154*0Sstevel@tonic-gate 		return (-1);
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	/* check for ownership */
157*0Sstevel@tonic-gate 	if (meta_check_ownership(*spp, ep) != 0)
158*0Sstevel@tonic-gate 		return (-1);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	/* get hotspares */
161*0Sstevel@tonic-gate 	if (metanamelist(spp, &nlp, argc, argv, ep) < 0) {
162*0Sstevel@tonic-gate 		goto out;
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/* add hotspares */
166*0Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
167*0Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 		if (meta_hs_add(*spp, hspnp, nlp, options, ep) != 0)
170*0Sstevel@tonic-gate 			goto out;
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 	rval = 0;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	/* cleanup, return success */
175*0Sstevel@tonic-gate out:
176*0Sstevel@tonic-gate 	if (hspnlp != NULL)
177*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
178*0Sstevel@tonic-gate 	if (nlp != NULL)
179*0Sstevel@tonic-gate 		metafreenamelist(nlp);
180*0Sstevel@tonic-gate 	return (rval);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate /*
184*0Sstevel@tonic-gate  * parse args and delete hotspares
185*0Sstevel@tonic-gate  */
186*0Sstevel@tonic-gate static int
187*0Sstevel@tonic-gate delete_hotspares(
188*0Sstevel@tonic-gate 	mdsetname_t	**spp,
189*0Sstevel@tonic-gate 	int		argc,
190*0Sstevel@tonic-gate 	char		*argv[],
191*0Sstevel@tonic-gate 	mdcmdopts_t	options,
192*0Sstevel@tonic-gate 	md_error_t	*ep
193*0Sstevel@tonic-gate )
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
196*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
197*0Sstevel@tonic-gate 	int		cnt;
198*0Sstevel@tonic-gate 	mdhspnamelist_t	*p;
199*0Sstevel@tonic-gate 	int		rval = -1;
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	/* get hotspare pool name(s) */
202*0Sstevel@tonic-gate 	if (argc < 1)
203*0Sstevel@tonic-gate 		usage(*spp, 1);
204*0Sstevel@tonic-gate 	if ((argc > 1) && is_all(argv[0])) {
205*0Sstevel@tonic-gate 		if ((*spp == NULL) &&
206*0Sstevel@tonic-gate 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
207*0Sstevel@tonic-gate 			return (-1);
208*0Sstevel@tonic-gate 		}
209*0Sstevel@tonic-gate 		/* check for ownership */
210*0Sstevel@tonic-gate 		assert(*spp != NULL);
211*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
212*0Sstevel@tonic-gate 			return (-1);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
215*0Sstevel@tonic-gate 			return (-1);
216*0Sstevel@tonic-gate 		} else if (cnt == 0) {
217*0Sstevel@tonic-gate 			return (mderror(ep, MDE_NO_HSPS, NULL));
218*0Sstevel@tonic-gate 		}
219*0Sstevel@tonic-gate 	} else if ((cnt = metahspnamelist(spp, &hspnlp, 1, &argv[0],
220*0Sstevel@tonic-gate 	    ep)) < 0) {
221*0Sstevel@tonic-gate 		return (-1);
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate 	assert(cnt > 0);
224*0Sstevel@tonic-gate 	--argc, ++argv;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	assert(*spp != NULL);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	/* grab set lock */
229*0Sstevel@tonic-gate 	if (meta_lock(*spp, TRUE, ep))
230*0Sstevel@tonic-gate 		return (-1);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	/* check for ownership */
233*0Sstevel@tonic-gate 	if (meta_check_ownership(*spp, ep) != 0)
234*0Sstevel@tonic-gate 		return (-1);
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	/* get hotspares */
237*0Sstevel@tonic-gate 	if (metanamelist(spp, &nlp, argc, argv, ep) < 0) {
238*0Sstevel@tonic-gate 		goto out;
239*0Sstevel@tonic-gate 	}
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	/* delete hotspares */
242*0Sstevel@tonic-gate 	cnt = 0;
243*0Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
244*0Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 		if (meta_hs_delete(*spp, hspnp, nlp, options, ep) != 0) {
247*0Sstevel@tonic-gate 			if (mdisdeverror(ep, MDE_INVAL_HS))
248*0Sstevel@tonic-gate 				mdclrerror(ep);
249*0Sstevel@tonic-gate 			else
250*0Sstevel@tonic-gate 				goto out;
251*0Sstevel@tonic-gate 		} else {
252*0Sstevel@tonic-gate 			++cnt;
253*0Sstevel@tonic-gate 		}
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	/* make sure we got some */
257*0Sstevel@tonic-gate 	if ((nlp != NULL) && (cnt == 0)) {
258*0Sstevel@tonic-gate 		(void) mddeverror(ep, MDE_INVAL_HS, nlp->namep->dev,
259*0Sstevel@tonic-gate 		    nlp->namep->cname);
260*0Sstevel@tonic-gate 		goto out;
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/* success */
264*0Sstevel@tonic-gate 	rval = 0;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	/* cleanup, return success */
267*0Sstevel@tonic-gate out:
268*0Sstevel@tonic-gate 	if (hspnlp != NULL)
269*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
270*0Sstevel@tonic-gate 	if (nlp != NULL)
271*0Sstevel@tonic-gate 		metafreenamelist(nlp);
272*0Sstevel@tonic-gate 	return (rval);
273*0Sstevel@tonic-gate }
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate /*
276*0Sstevel@tonic-gate  * parse args and enable hotspares
277*0Sstevel@tonic-gate  */
278*0Sstevel@tonic-gate static int
279*0Sstevel@tonic-gate enable_hotspares(
280*0Sstevel@tonic-gate 	mdsetname_t	**spp,
281*0Sstevel@tonic-gate 	int		argc,
282*0Sstevel@tonic-gate 	char		*argv[],
283*0Sstevel@tonic-gate 	mdcmdopts_t	options,
284*0Sstevel@tonic-gate 	md_error_t	*ep
285*0Sstevel@tonic-gate )
286*0Sstevel@tonic-gate {
287*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
288*0Sstevel@tonic-gate 	int		rval = -1;
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	/* enable hotspares */
291*0Sstevel@tonic-gate 	if (argc < 1)
292*0Sstevel@tonic-gate 		usage(*spp, 1);
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	/* get list of hotspares */
295*0Sstevel@tonic-gate 	if (metanamelist(spp, &nlp, argc, argv, ep) < 0)
296*0Sstevel@tonic-gate 		goto out;
297*0Sstevel@tonic-gate 	assert(nlp != NULL);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	assert(*spp != NULL);
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	/* grab set lock */
302*0Sstevel@tonic-gate 	if (meta_lock(*spp, TRUE, ep))
303*0Sstevel@tonic-gate 		return (-1);
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	/* check for ownership */
306*0Sstevel@tonic-gate 	if (meta_check_ownership(*spp, ep) != 0)
307*0Sstevel@tonic-gate 		return (-1);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	/* enable hotspares */
310*0Sstevel@tonic-gate 	rval = meta_hs_enable(*spp, nlp, options, ep);
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	/* cleanup, return success */
313*0Sstevel@tonic-gate out:
314*0Sstevel@tonic-gate 	metafreenamelist(nlp);
315*0Sstevel@tonic-gate 	return (rval);
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate /*
319*0Sstevel@tonic-gate  * parse args and replace hotspares
320*0Sstevel@tonic-gate  */
321*0Sstevel@tonic-gate static int
322*0Sstevel@tonic-gate replace_hotspares(
323*0Sstevel@tonic-gate 	mdsetname_t	**spp,
324*0Sstevel@tonic-gate 	int		argc,
325*0Sstevel@tonic-gate 	char		*argv[],
326*0Sstevel@tonic-gate 	mdcmdopts_t	options,
327*0Sstevel@tonic-gate 	md_error_t	*ep
328*0Sstevel@tonic-gate )
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
331*0Sstevel@tonic-gate 	int		cnt;
332*0Sstevel@tonic-gate 	mdname_t	*oldnp;
333*0Sstevel@tonic-gate 	mdname_t	*newnp;
334*0Sstevel@tonic-gate 	mdhspnamelist_t	*p;
335*0Sstevel@tonic-gate 	int		rval = -1;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	/* get hotspare pool name(s) */
338*0Sstevel@tonic-gate 	if (argc != 3)
339*0Sstevel@tonic-gate 		usage(*spp, 1);
340*0Sstevel@tonic-gate 	if (is_all(argv[0])) {
341*0Sstevel@tonic-gate 		if ((*spp == NULL) &&
342*0Sstevel@tonic-gate 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
343*0Sstevel@tonic-gate 			return (-1);
344*0Sstevel@tonic-gate 		}
345*0Sstevel@tonic-gate 		/* check for ownership */
346*0Sstevel@tonic-gate 		assert(*spp != NULL);
347*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
348*0Sstevel@tonic-gate 			return (-1);
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
351*0Sstevel@tonic-gate 			return (-1);
352*0Sstevel@tonic-gate 		} else if (cnt == 0) {
353*0Sstevel@tonic-gate 			return (mderror(ep, MDE_NO_HSPS, NULL));
354*0Sstevel@tonic-gate 		}
355*0Sstevel@tonic-gate 	} else if ((cnt = metahspnamelist(spp, &hspnlp, 1, &argv[0],
356*0Sstevel@tonic-gate 	    ep)) < 0) {
357*0Sstevel@tonic-gate 		return (-1);
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 	assert(cnt > 0);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	assert(*spp != NULL);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/* grab set lock */
364*0Sstevel@tonic-gate 	if (meta_lock(*spp, TRUE, ep))
365*0Sstevel@tonic-gate 		return (-1);
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	/* check for ownership */
368*0Sstevel@tonic-gate 	if (meta_check_ownership(*spp, ep) != 0)
369*0Sstevel@tonic-gate 		return (-1);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	/* get old component */
372*0Sstevel@tonic-gate 	if ((oldnp = metaname(spp, argv[1], ep)) == NULL)
373*0Sstevel@tonic-gate 		goto out;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	/* get new component */
376*0Sstevel@tonic-gate 	if ((newnp = metaname(spp, argv[2], ep)) == NULL)
377*0Sstevel@tonic-gate 		goto out;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	/* replace hotspares */
380*0Sstevel@tonic-gate 	cnt = 0;
381*0Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
382*0Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 		if (meta_hs_replace(*spp, hspnp, oldnp, newnp, options, ep)
385*0Sstevel@tonic-gate 		    != 0) {
386*0Sstevel@tonic-gate 			if (mdisdeverror(ep, MDE_INVAL_HS))
387*0Sstevel@tonic-gate 				mdclrerror(ep);
388*0Sstevel@tonic-gate 			else
389*0Sstevel@tonic-gate 				goto out;
390*0Sstevel@tonic-gate 		} else {
391*0Sstevel@tonic-gate 			++cnt;
392*0Sstevel@tonic-gate 		}
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	/* make sure we got some */
396*0Sstevel@tonic-gate 	if (cnt == 0) {
397*0Sstevel@tonic-gate 		(void) mddeverror(ep, MDE_INVAL_HS, oldnp->dev, oldnp->cname);
398*0Sstevel@tonic-gate 		goto out;
399*0Sstevel@tonic-gate 	}
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	/* success */
402*0Sstevel@tonic-gate 	rval = 0;
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	/* cleanup, return success */
405*0Sstevel@tonic-gate out:
406*0Sstevel@tonic-gate 	if (hspnlp != NULL)
407*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
408*0Sstevel@tonic-gate 	return (rval);
409*0Sstevel@tonic-gate }
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate /*
412*0Sstevel@tonic-gate  * print_hsp_devid will collect the information for each underlying
413*0Sstevel@tonic-gate  * physical device for all the hotspare pools and print out the
414*0Sstevel@tonic-gate  * device relocation information
415*0Sstevel@tonic-gate  * INPUT:
416*0Sstevel@tonic-gate  *	mdsetname_t *sp			set the hsp is in
417*0Sstevel@tonic-gate  *	mdhspnamelist_t *hspnlp		list of hsp
418*0Sstevel@tonic-gate  *	FILE	*fp			where to print to
419*0Sstevel@tonic-gate  *	md_error_t	*ep		errors
420*0Sstevel@tonic-gate  * RETURN:
421*0Sstevel@tonic-gate  *	0 	SUCCESS
422*0Sstevel@tonic-gate  *	-1	ERROR
423*0Sstevel@tonic-gate  */
424*0Sstevel@tonic-gate static int
425*0Sstevel@tonic-gate print_hsp_devid(
426*0Sstevel@tonic-gate 	mdsetname_t	*sp,
427*0Sstevel@tonic-gate 	mdhspnamelist_t *hspnlp,
428*0Sstevel@tonic-gate 	FILE		*fp,
429*0Sstevel@tonic-gate 	md_error_t	*ep
430*0Sstevel@tonic-gate )
431*0Sstevel@tonic-gate {
432*0Sstevel@tonic-gate 	mddevid_t	*ldevidp = NULL;
433*0Sstevel@tonic-gate 	int		retval = 0;
434*0Sstevel@tonic-gate 	mdhspnamelist_t	*p;
435*0Sstevel@tonic-gate 	mddevid_t	*nextp;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	/* for all hotspare pools */
438*0Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
439*0Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
440*0Sstevel@tonic-gate 		uint_t		hsi;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 		/* for all hotspares within a pool */
443*0Sstevel@tonic-gate 		for (hsi = 0;
444*0Sstevel@tonic-gate 		    hsi < hspnp->unitp->hotspares.hotspares_len; hsi++) {
445*0Sstevel@tonic-gate 			mdname_t	*hsname;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 			hsname =
448*0Sstevel@tonic-gate 			    hspnp->unitp->hotspares.hotspares_val[hsi].hsnamep;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 			meta_create_non_dup_list(hsname, &ldevidp);
451*0Sstevel@tonic-gate 		}
452*0Sstevel@tonic-gate 	}
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	retval = meta_print_devid(sp, fp, ldevidp, ep);
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	/* cleanup */
457*0Sstevel@tonic-gate 	for (nextp = ldevidp; nextp != NULL; ldevidp = nextp) {
458*0Sstevel@tonic-gate 		Free(ldevidp->ctdname);
459*0Sstevel@tonic-gate 		nextp = ldevidp->next;
460*0Sstevel@tonic-gate 		Free(ldevidp);
461*0Sstevel@tonic-gate 	}
462*0Sstevel@tonic-gate 	return (retval);
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate /*
466*0Sstevel@tonic-gate  * parse args and status hotspares
467*0Sstevel@tonic-gate  */
468*0Sstevel@tonic-gate static int
469*0Sstevel@tonic-gate status_hotspares(
470*0Sstevel@tonic-gate 	mdsetname_t	**spp,
471*0Sstevel@tonic-gate 	int		argc,
472*0Sstevel@tonic-gate 	char		*argv[],
473*0Sstevel@tonic-gate 	md_error_t	*ep
474*0Sstevel@tonic-gate )
475*0Sstevel@tonic-gate {
476*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
477*0Sstevel@tonic-gate 	int		cnt;
478*0Sstevel@tonic-gate 	mdhspnamelist_t	*p;
479*0Sstevel@tonic-gate 	int		rval = -1;
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	/* get hotspare pool name(s) */
482*0Sstevel@tonic-gate 	if (argc == 0) {
483*0Sstevel@tonic-gate 		if ((*spp == NULL) &&
484*0Sstevel@tonic-gate 		    ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL)) {
485*0Sstevel@tonic-gate 			return (-1);
486*0Sstevel@tonic-gate 		}
487*0Sstevel@tonic-gate 		/* check for ownership */
488*0Sstevel@tonic-gate 		assert(*spp != NULL);
489*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
490*0Sstevel@tonic-gate 			return (-1);
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(*spp, &hspnlp, 0, ep)) < 0) {
493*0Sstevel@tonic-gate 			return (-1);
494*0Sstevel@tonic-gate 		} else if (cnt == 0) {
495*0Sstevel@tonic-gate 			return (mderror(ep, MDE_NO_HSPS, NULL));
496*0Sstevel@tonic-gate 		}
497*0Sstevel@tonic-gate 	} else if ((cnt = metahspnamelist(spp, &hspnlp, argc, argv, ep)) < 0) {
498*0Sstevel@tonic-gate 		return (-1);
499*0Sstevel@tonic-gate 	}
500*0Sstevel@tonic-gate 	assert(cnt > 0);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	/* check for ownership */
503*0Sstevel@tonic-gate 	assert(*spp != NULL);
504*0Sstevel@tonic-gate 	if (meta_check_ownership(*spp, ep) != 0)
505*0Sstevel@tonic-gate 		return (-1);
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	/* status hotspare pools */
508*0Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
509*0Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 		if (status_hsp(*spp, hspnp, ep) != 0)
512*0Sstevel@tonic-gate 			goto out;
513*0Sstevel@tonic-gate 	}
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	if (print_hsp_devid(*spp, hspnlp, stdout, ep) == 0) {
516*0Sstevel@tonic-gate 		rval = 0;
517*0Sstevel@tonic-gate 	}
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	/* cleanup, return success */
520*0Sstevel@tonic-gate out:
521*0Sstevel@tonic-gate 	if (hspnlp != NULL)
522*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
523*0Sstevel@tonic-gate 	return (rval);
524*0Sstevel@tonic-gate }
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate /*
527*0Sstevel@tonic-gate  * parse args and doit
528*0Sstevel@tonic-gate  */
529*0Sstevel@tonic-gate int
530*0Sstevel@tonic-gate main(
531*0Sstevel@tonic-gate 	int		argc,
532*0Sstevel@tonic-gate 	char		**argv
533*0Sstevel@tonic-gate )
534*0Sstevel@tonic-gate {
535*0Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
536*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
537*0Sstevel@tonic-gate 	enum metahs_op	which_op = NONE;
538*0Sstevel@tonic-gate 	mdcmdopts_t	options = (MDCMD_PRINT | MDCMD_DOIT);
539*0Sstevel@tonic-gate 	int		c;
540*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
541*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
542*0Sstevel@tonic-gate 	int		error;
543*0Sstevel@tonic-gate 	bool_t		called_thru_rpc = FALSE;
544*0Sstevel@tonic-gate 	char		*cp;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	/*
547*0Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
548*0Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
549*0Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
550*0Sstevel@tonic-gate 	 * something.
551*0Sstevel@tonic-gate 	 */
552*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
553*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
554*0Sstevel@tonic-gate #endif
555*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
556*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
560*0Sstevel@tonic-gate 		if (sdssc_bind_library() == SDSSC_OKAY)
561*0Sstevel@tonic-gate 			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
562*0Sstevel@tonic-gate 						&error) == SDSSC_PROXY_DONE)
563*0Sstevel@tonic-gate 				exit(error);
564*0Sstevel@tonic-gate 	} else {
565*0Sstevel@tonic-gate 		*cp = '\0'; /* cut off ".rpc_call" */
566*0Sstevel@tonic-gate 		called_thru_rpc = TRUE;
567*0Sstevel@tonic-gate 	}
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	/* initialize */
570*0Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
571*0Sstevel@tonic-gate 		mde_perror(ep, "");
572*0Sstevel@tonic-gate 		md_exit(sp, 1);
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	/* parse args */
576*0Sstevel@tonic-gate 	optind = 1;
577*0Sstevel@tonic-gate 	opterr = 1;
578*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "hs:aderin?")) != -1) {
579*0Sstevel@tonic-gate 		switch (c) {
580*0Sstevel@tonic-gate 		case 'h':
581*0Sstevel@tonic-gate 			usage(sp, 0);
582*0Sstevel@tonic-gate 			break;
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 		case 's':
585*0Sstevel@tonic-gate 			sname = optarg;
586*0Sstevel@tonic-gate 			break;
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 		case 'a':
589*0Sstevel@tonic-gate 			if (which_op != NONE)
590*0Sstevel@tonic-gate 				usage(sp, 1);
591*0Sstevel@tonic-gate 			which_op = ADD_A_HS;
592*0Sstevel@tonic-gate 			break;
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 		case 'd':
595*0Sstevel@tonic-gate 			if (which_op != NONE)
596*0Sstevel@tonic-gate 				usage(sp, 1);
597*0Sstevel@tonic-gate 			which_op = DELETE_A_HS;
598*0Sstevel@tonic-gate 			break;
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 		case 'e':
601*0Sstevel@tonic-gate 			if (which_op != NONE)
602*0Sstevel@tonic-gate 				usage(sp, 1);
603*0Sstevel@tonic-gate 			which_op = ENABLE_A_HS;
604*0Sstevel@tonic-gate 			break;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 		case 'r':
607*0Sstevel@tonic-gate 			if (which_op != NONE)
608*0Sstevel@tonic-gate 				usage(sp, 1);
609*0Sstevel@tonic-gate 			which_op = REPLACE_A_HS;
610*0Sstevel@tonic-gate 			break;
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 		case 'i':
613*0Sstevel@tonic-gate 			if (which_op != NONE)
614*0Sstevel@tonic-gate 				usage(sp, 1);
615*0Sstevel@tonic-gate 			which_op = STATUS_A_HSP;
616*0Sstevel@tonic-gate 			break;
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 		case 'n':
619*0Sstevel@tonic-gate 			if (called_thru_rpc == TRUE) {
620*0Sstevel@tonic-gate 				options &= ~MDCMD_DOIT;
621*0Sstevel@tonic-gate 			} else {
622*0Sstevel@tonic-gate 				usage(sp, 1);
623*0Sstevel@tonic-gate 			}
624*0Sstevel@tonic-gate 			break;
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		case '?':
628*0Sstevel@tonic-gate 			if (optopt == '?')
629*0Sstevel@tonic-gate 				usage(sp, 0);
630*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
631*0Sstevel@tonic-gate 		default:
632*0Sstevel@tonic-gate 			usage(sp, 1);
633*0Sstevel@tonic-gate 			break;
634*0Sstevel@tonic-gate 		}
635*0Sstevel@tonic-gate 	}
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	/* get set context */
638*0Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
639*0Sstevel@tonic-gate 		mde_perror(ep, "");
640*0Sstevel@tonic-gate 		md_exit(sp, 1);
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	/*
644*0Sstevel@tonic-gate 	 * Send the command to all nodes if the -s argument refers to a MN
645*0Sstevel@tonic-gate 	 * set or the next argument refers to MN set hotspare name ( argc
646*0Sstevel@tonic-gate 	 * greater than optind if there is a next argument)
647*0Sstevel@tonic-gate 	 */
648*0Sstevel@tonic-gate 	if ((called_thru_rpc == FALSE) &&
649*0Sstevel@tonic-gate 	    (meta_is_mn_set(sp, ep) || ((argc > optind) &&
650*0Sstevel@tonic-gate 	    meta_is_mn_name(&sp, argv[optind], ep)))) {
651*0Sstevel@tonic-gate 		int	i;
652*0Sstevel@tonic-gate 		int	newargc;
653*0Sstevel@tonic-gate 		int	result;
654*0Sstevel@tonic-gate 		char	**newargv;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		/*
657*0Sstevel@tonic-gate 		 * If we are dealing with a MN set and we were not
658*0Sstevel@tonic-gate 		 * called thru an rpc call, we are just to send this
659*0Sstevel@tonic-gate 		 * command string to the master of the set and let it
660*0Sstevel@tonic-gate 		 * deal with it.
661*0Sstevel@tonic-gate 		 * First we send out a dryrun version of this command.
662*0Sstevel@tonic-gate 		 * If that returns success, we know it succeeded on all
663*0Sstevel@tonic-gate 		 * nodes and it is safe to do the real command now.
664*0Sstevel@tonic-gate 		 */
665*0Sstevel@tonic-gate 		newargv = calloc(argc+1, sizeof (char *));
666*0Sstevel@tonic-gate 		newargv[0] = "metahs";
667*0Sstevel@tonic-gate 		newargv[1] = "-n"; /* always do "-n" first */
668*0Sstevel@tonic-gate 		newargc = 2;
669*0Sstevel@tonic-gate 		for (i = 1; i < argc; i++, newargc++)
670*0Sstevel@tonic-gate 			newargv[newargc] = argv[i];
671*0Sstevel@tonic-gate 		result = meta_mn_send_command(sp, newargc, newargv,
672*0Sstevel@tonic-gate 		    MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep);
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 		/* If we found a problem don't do it for real */
675*0Sstevel@tonic-gate 		if (result != 0) {
676*0Sstevel@tonic-gate 			md_exit(sp, result);
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 		/*
680*0Sstevel@tonic-gate 		 * Do it for real now. Remove "-n" from the arguments and
681*0Sstevel@tonic-gate 		 * MD_DRYRUN from the flags. If this fails the master must panic
682*0Sstevel@tonic-gate 		 * as the mddbs may be inconsistent.
683*0Sstevel@tonic-gate 		 */
684*0Sstevel@tonic-gate 		newargv[1] = ""; /* this was "-n" before */
685*0Sstevel@tonic-gate 		result = meta_mn_send_command(sp, newargc, newargv,
686*0Sstevel@tonic-gate 		    MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
687*0Sstevel@tonic-gate 		    NO_CONTEXT_STRING, ep);
688*0Sstevel@tonic-gate 		free(newargv);
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 		/* No further action required */
691*0Sstevel@tonic-gate 		md_exit(sp, result);
692*0Sstevel@tonic-gate 	}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	argc -= optind;
695*0Sstevel@tonic-gate 	argv += optind;
696*0Sstevel@tonic-gate 	if (which_op == NONE)
697*0Sstevel@tonic-gate 		usage(sp, 1);
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	if (which_op == STATUS_A_HSP) {
700*0Sstevel@tonic-gate 		if (status_hotspares(&sp, argc, argv, ep) != 0) {
701*0Sstevel@tonic-gate 			mde_perror(ep, "");
702*0Sstevel@tonic-gate 			md_exit(sp, 1);
703*0Sstevel@tonic-gate 		}
704*0Sstevel@tonic-gate 		md_exit(sp, 0);
705*0Sstevel@tonic-gate 	}
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
708*0Sstevel@tonic-gate 		mde_perror(ep, "");
709*0Sstevel@tonic-gate 		md_exit(sp, 1);
710*0Sstevel@tonic-gate 	}
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	/* dispatch */
714*0Sstevel@tonic-gate 	switch (which_op) {
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	case ADD_A_HS:
717*0Sstevel@tonic-gate 		if (add_hotspares(&sp, argc, argv, options, ep) != 0) {
718*0Sstevel@tonic-gate 			mde_perror(ep, "");
719*0Sstevel@tonic-gate 			md_exit(sp, 1);
720*0Sstevel@tonic-gate 		}
721*0Sstevel@tonic-gate 		break;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	case DELETE_A_HS:
724*0Sstevel@tonic-gate 		if (delete_hotspares(&sp, argc, argv, options, ep) != 0) {
725*0Sstevel@tonic-gate 			mde_perror(ep, "");
726*0Sstevel@tonic-gate 			md_exit(sp, 1);
727*0Sstevel@tonic-gate 		}
728*0Sstevel@tonic-gate 		break;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	case ENABLE_A_HS:
731*0Sstevel@tonic-gate 		if (enable_hotspares(&sp, argc, argv, options, ep) != 0) {
732*0Sstevel@tonic-gate 			mde_perror(ep, "");
733*0Sstevel@tonic-gate 			md_exit(sp, 1);
734*0Sstevel@tonic-gate 		}
735*0Sstevel@tonic-gate 		break;
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	case REPLACE_A_HS:
738*0Sstevel@tonic-gate 		if (replace_hotspares(&sp, argc, argv, options, ep) != 0) {
739*0Sstevel@tonic-gate 			mde_perror(ep, "");
740*0Sstevel@tonic-gate 			md_exit(sp, 1);
741*0Sstevel@tonic-gate 		}
742*0Sstevel@tonic-gate 		break;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	default:
745*0Sstevel@tonic-gate 		assert(0);
746*0Sstevel@tonic-gate 		break;
747*0Sstevel@tonic-gate 	}
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	/* update md.cf */
750*0Sstevel@tonic-gate out:
751*0Sstevel@tonic-gate 	if (meta_update_md_cf(sp, ep) != 0) {
752*0Sstevel@tonic-gate 		mde_perror(ep, "");
753*0Sstevel@tonic-gate 		md_exit(sp, 1);
754*0Sstevel@tonic-gate 	}
755*0Sstevel@tonic-gate 	md_exit(sp, 0);
756*0Sstevel@tonic-gate 	/*NOTREACHED*/
757*0Sstevel@tonic-gate 	return (0);
758*0Sstevel@tonic-gate }
759