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  * attach submirrors
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <meta.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <sdssc.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * print usage message
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate static void
41*0Sstevel@tonic-gate usage(
42*0Sstevel@tonic-gate 	mdsetname_t	*sp,
43*0Sstevel@tonic-gate 	int		eval
44*0Sstevel@tonic-gate )
45*0Sstevel@tonic-gate {
46*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\
47*0Sstevel@tonic-gate usage:	%s [-s setname] mirror [metadevice]\n\
48*0Sstevel@tonic-gate 	%s [-s setname] [-i interlace] concat/stripe component...\n\
49*0Sstevel@tonic-gate 	%s [-s setname] RAID component...\n\
50*0Sstevel@tonic-gate 	%s [-s setname] [-A alignment] softpart size|all\n"),
51*0Sstevel@tonic-gate 	    myname, myname, myname, myname);
52*0Sstevel@tonic-gate 	md_exit(sp, eval);
53*0Sstevel@tonic-gate }
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * attach more space to a soft partition
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate static int
59*0Sstevel@tonic-gate sp_attach(
60*0Sstevel@tonic-gate 	mdsetname_t	**spp,
61*0Sstevel@tonic-gate 	mdname_t	*spnp,
62*0Sstevel@tonic-gate 	int		argc,
63*0Sstevel@tonic-gate 	char		*argv[],
64*0Sstevel@tonic-gate 	mdcmdopts_t	options,
65*0Sstevel@tonic-gate 	md_error_t	*ep
66*0Sstevel@tonic-gate )
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	int		c;
69*0Sstevel@tonic-gate 	sp_ext_offset_t	alignment = 0;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	/* reset and parse args */
72*0Sstevel@tonic-gate 	optind = 1;
73*0Sstevel@tonic-gate 	opterr = 1;
74*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ns:A:")) != -1) {
75*0Sstevel@tonic-gate 		switch (c) {
76*0Sstevel@tonic-gate 		case 'n':
77*0Sstevel@tonic-gate 		case 's':
78*0Sstevel@tonic-gate 			break;
79*0Sstevel@tonic-gate 		case 'A':
80*0Sstevel@tonic-gate 			if (meta_sp_parsesize(optarg, &alignment) == -1) {
81*0Sstevel@tonic-gate 			    usage(*spp, 1);
82*0Sstevel@tonic-gate 			    /* NOTREACHED */
83*0Sstevel@tonic-gate 			}
84*0Sstevel@tonic-gate 			break;
85*0Sstevel@tonic-gate 		default:
86*0Sstevel@tonic-gate 			usage(*spp, 1);
87*0Sstevel@tonic-gate 			/* NOTREACHED */
88*0Sstevel@tonic-gate 			break;
89*0Sstevel@tonic-gate 		}
90*0Sstevel@tonic-gate 	}
91*0Sstevel@tonic-gate 	argc -= optind + 1;
92*0Sstevel@tonic-gate 	argv += optind + 1;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	if (argc != 1)
95*0Sstevel@tonic-gate 		usage(*spp, 1);
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	if (meta_sp_attach(*spp, spnp, argv[0], options, alignment, ep) != 0) {
98*0Sstevel@tonic-gate 		return (-1);
99*0Sstevel@tonic-gate 	}
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	/* update md.cf file */
102*0Sstevel@tonic-gate 	if (meta_update_md_cf(*spp, ep) != 0)
103*0Sstevel@tonic-gate 		return (-1);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	return (0);
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * attach components to stripe
109*0Sstevel@tonic-gate  */
110*0Sstevel@tonic-gate static int
111*0Sstevel@tonic-gate stripe_attach(
112*0Sstevel@tonic-gate 	mdsetname_t	**spp,
113*0Sstevel@tonic-gate 	mdname_t	*stripenp,
114*0Sstevel@tonic-gate 	int		argc,
115*0Sstevel@tonic-gate 	char		*argv[],
116*0Sstevel@tonic-gate 	mdcmdopts_t	options,
117*0Sstevel@tonic-gate 	md_error_t	*ep
118*0Sstevel@tonic-gate )
119*0Sstevel@tonic-gate {
120*0Sstevel@tonic-gate 	diskaddr_t	interlace = 0;
121*0Sstevel@tonic-gate 	int		c;
122*0Sstevel@tonic-gate 	mdnamelist_t	*compnlp = NULL;
123*0Sstevel@tonic-gate 	mdnamelist_t	*p;
124*0Sstevel@tonic-gate 	mdname_t	*currootnp;
125*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
126*0Sstevel@tonic-gate 	md_row_t	*rp;
127*0Sstevel@tonic-gate 	md_comp_t	*cp;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/* reset and parse args */
131*0Sstevel@tonic-gate 	optind = 1;
132*0Sstevel@tonic-gate 	opterr = 1;
133*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "s:ani:")) != -1) {
134*0Sstevel@tonic-gate 		switch (c) {
135*0Sstevel@tonic-gate 		case 'n':
136*0Sstevel@tonic-gate 		case 's':
137*0Sstevel@tonic-gate 			break;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 		case 'a':
140*0Sstevel@tonic-gate 			break;	/* obsolete */
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 		case 'i':
143*0Sstevel@tonic-gate 			if (parse_interlace(stripenp->cname, optarg,
144*0Sstevel@tonic-gate 			    &interlace, ep) != 0) {
145*0Sstevel@tonic-gate 				return (-1);
146*0Sstevel@tonic-gate 			}
147*0Sstevel@tonic-gate 			if (meta_stripe_check_interlace(interlace,
148*0Sstevel@tonic-gate 			    stripenp->cname, ep))
149*0Sstevel@tonic-gate 				return (-1);
150*0Sstevel@tonic-gate 			break;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		default:
153*0Sstevel@tonic-gate 			usage(*spp, 1);
154*0Sstevel@tonic-gate 			/*NOTREACHED*/
155*0Sstevel@tonic-gate 			break;
156*0Sstevel@tonic-gate 		}
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	argc -= optind + 1;
160*0Sstevel@tonic-gate 	argv += optind + 1;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	if (argc <= 0)
163*0Sstevel@tonic-gate 		usage(*spp, 1);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/* get list of components */
166*0Sstevel@tonic-gate 	if (metanamelist(spp, &compnlp, argc, argv, ep) < 0)
167*0Sstevel@tonic-gate 		return (-1);
168*0Sstevel@tonic-gate 	assert(compnlp != NULL);
169*0Sstevel@tonic-gate 	for (p = compnlp; (p != NULL); p = p->next) {
170*0Sstevel@tonic-gate 		mdname_t	*compnp = p->namep;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 		/* see if we are a soft partition */
173*0Sstevel@tonic-gate 		if (meta_sp_issp(*spp, compnp, ep) != 0) {
174*0Sstevel@tonic-gate 			/* nope, check component */
175*0Sstevel@tonic-gate 			if (metachkcomp(compnp, ep) != 0)
176*0Sstevel@tonic-gate 				return (-1);
177*0Sstevel@tonic-gate 		}
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	/* get root device */
181*0Sstevel@tonic-gate 	if ((currootnp = meta_get_current_root_dev(*spp, ep)) != NULL) {
182*0Sstevel@tonic-gate 		/*
183*0Sstevel@tonic-gate 		 * Root is either a stripe or a slice
184*0Sstevel@tonic-gate 		 * If root device is the 1st component of the stripe
185*0Sstevel@tonic-gate 		 * Then fail as root cannot be expanded
186*0Sstevel@tonic-gate 		 */
187*0Sstevel@tonic-gate 		if ((stripep = meta_get_stripe(*spp, stripenp, ep)) == NULL)
188*0Sstevel@tonic-gate 			return (-1);
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 		rp = &stripep->rows.rows_val[0];
191*0Sstevel@tonic-gate 		cp = &rp->comps.comps_val[0];
192*0Sstevel@tonic-gate 		if (metachkcomp(cp->compnamep, ep) == 0) {
193*0Sstevel@tonic-gate 			/* Component is a disk */
194*0Sstevel@tonic-gate 			if (strcmp(currootnp->cname,
195*0Sstevel@tonic-gate 			    cp->compnamep->cname) == 0) {
196*0Sstevel@tonic-gate 				md_eprintf(gettext(
197*0Sstevel@tonic-gate 				"%s: volume mounted as root cannot be "
198*0Sstevel@tonic-gate 				"expanded\n"), stripenp->cname);
199*0Sstevel@tonic-gate 				md_exit(*spp, 1);
200*0Sstevel@tonic-gate 			}
201*0Sstevel@tonic-gate 		}
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	/* attach components */
205*0Sstevel@tonic-gate 	if (meta_stripe_attach(*spp, stripenp, compnlp, interlace, options,
206*0Sstevel@tonic-gate 	    ep) != 0) {
207*0Sstevel@tonic-gate 		return (-1);
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	/* update md.cf file */
211*0Sstevel@tonic-gate 	if (meta_update_md_cf(*spp, ep) != 0)
212*0Sstevel@tonic-gate 		return (-1);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	/* return success */
215*0Sstevel@tonic-gate 	return (0);
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate  * attach components to raid
220*0Sstevel@tonic-gate  */
221*0Sstevel@tonic-gate static int
222*0Sstevel@tonic-gate raid_attach(
223*0Sstevel@tonic-gate 	mdsetname_t	**spp,
224*0Sstevel@tonic-gate 	mdname_t	*raidnp,
225*0Sstevel@tonic-gate 	int		argc,
226*0Sstevel@tonic-gate 	char		*argv[],
227*0Sstevel@tonic-gate 	mdcmdopts_t	options,
228*0Sstevel@tonic-gate 	md_error_t	*ep
229*0Sstevel@tonic-gate )
230*0Sstevel@tonic-gate {
231*0Sstevel@tonic-gate 	int		c;
232*0Sstevel@tonic-gate 	mdnamelist_t	*compnlp = NULL;
233*0Sstevel@tonic-gate 	mdnamelist_t	*p;
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/* reset and parse args */
236*0Sstevel@tonic-gate 	optind = 1;
237*0Sstevel@tonic-gate 	opterr = 1;
238*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "s:ai:")) != -1) {
239*0Sstevel@tonic-gate 		switch (c) {
240*0Sstevel@tonic-gate 		case 'n':
241*0Sstevel@tonic-gate 		case 's':
242*0Sstevel@tonic-gate 			break;
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 		case 'a':
245*0Sstevel@tonic-gate 			break;	/* obsolete */
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 		default:
248*0Sstevel@tonic-gate 			usage(*spp, 1);
249*0Sstevel@tonic-gate 			/*NOTREACHED*/
250*0Sstevel@tonic-gate 			break;
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 	argc -= optind + 1;
254*0Sstevel@tonic-gate 	argv += optind + 1;
255*0Sstevel@tonic-gate 	if (argc <= 0)
256*0Sstevel@tonic-gate 		usage(*spp, 1);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	/* get list of components */
259*0Sstevel@tonic-gate 	if (metanamelist(spp, &compnlp, argc, argv, ep) < 0)
260*0Sstevel@tonic-gate 		return (-1);
261*0Sstevel@tonic-gate 	assert(compnlp != NULL);
262*0Sstevel@tonic-gate 	for (p = compnlp; (p != NULL); p = p->next) {
263*0Sstevel@tonic-gate 		mdname_t	*compnp = p->namep;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 		/* check for soft partitions */
266*0Sstevel@tonic-gate 		if (meta_sp_issp(*spp, compnp, ep) != 0) {
267*0Sstevel@tonic-gate 			/* check disk */
268*0Sstevel@tonic-gate 			if (metachkcomp(compnp, ep) != 0)
269*0Sstevel@tonic-gate 				return (-1);
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 	}
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	/* attach components */
274*0Sstevel@tonic-gate 	if (meta_raid_attach(*spp, raidnp, compnlp, options, ep) != 0)
275*0Sstevel@tonic-gate 		return (-1);
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	/* update md.cf file */
278*0Sstevel@tonic-gate 	if (meta_update_md_cf(*spp, ep) != 0)
279*0Sstevel@tonic-gate 		return (-1);
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	/* return success */
282*0Sstevel@tonic-gate 	return (0);
283*0Sstevel@tonic-gate }
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate /*
286*0Sstevel@tonic-gate  * attach submirror to mirror
287*0Sstevel@tonic-gate  */
288*0Sstevel@tonic-gate static int
289*0Sstevel@tonic-gate mirror_attach(
290*0Sstevel@tonic-gate 	mdsetname_t	**spp,
291*0Sstevel@tonic-gate 	mdname_t	*mirnp,
292*0Sstevel@tonic-gate 	int		argc,
293*0Sstevel@tonic-gate 	char		*argv[],
294*0Sstevel@tonic-gate 	mdcmdopts_t	options,
295*0Sstevel@tonic-gate 	md_error_t	*ep
296*0Sstevel@tonic-gate )
297*0Sstevel@tonic-gate {
298*0Sstevel@tonic-gate 	int		c;
299*0Sstevel@tonic-gate 	mdname_t	*submirnp;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	/* reset and parse args */
302*0Sstevel@tonic-gate 	optind = 1;
303*0Sstevel@tonic-gate 	opterr = 1;
304*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ns:")) != -1) {
305*0Sstevel@tonic-gate 		switch (c) {
306*0Sstevel@tonic-gate 		case 'n':
307*0Sstevel@tonic-gate 		case 's':
308*0Sstevel@tonic-gate 			break;
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 		default:
311*0Sstevel@tonic-gate 			usage(*spp, 1);
312*0Sstevel@tonic-gate 			/*NOTREACHED*/
313*0Sstevel@tonic-gate 			break;
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate 	argc -= optind + 1;
317*0Sstevel@tonic-gate 	argv += optind + 1;
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	/* get submirror */
320*0Sstevel@tonic-gate 	if (argc == 1) {
321*0Sstevel@tonic-gate 		if (((submirnp = metaname(spp, argv[0], ep)) == NULL) ||
322*0Sstevel@tonic-gate 		    (metachkmeta(submirnp, ep) != 0)) {
323*0Sstevel@tonic-gate 			return (-1);
324*0Sstevel@tonic-gate 		}
325*0Sstevel@tonic-gate 	} else if (argc == 0) {
326*0Sstevel@tonic-gate 		submirnp = NULL;
327*0Sstevel@tonic-gate 	} else {
328*0Sstevel@tonic-gate 		usage(*spp, 1);
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	/* attach submirror */
332*0Sstevel@tonic-gate 	if (meta_mirror_attach(*spp, mirnp, submirnp, options, ep) != 0)
333*0Sstevel@tonic-gate 		return (-1);
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	/* update md.cf file */
336*0Sstevel@tonic-gate 	if (meta_update_md_cf(*spp, ep) != 0)
337*0Sstevel@tonic-gate 		return (-1);
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	/* return success */
340*0Sstevel@tonic-gate 	return (0);
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate /*
344*0Sstevel@tonic-gate  * attach devices
345*0Sstevel@tonic-gate  */
346*0Sstevel@tonic-gate int
347*0Sstevel@tonic-gate main(
348*0Sstevel@tonic-gate 	int		argc,
349*0Sstevel@tonic-gate 	char		*argv[]
350*0Sstevel@tonic-gate )
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate 	char		*sname = NULL;
353*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
354*0Sstevel@tonic-gate 	mdcmdopts_t	options = (MDCMD_PRINT|MDCMD_DOIT);
355*0Sstevel@tonic-gate 	mdname_t	*np;
356*0Sstevel@tonic-gate 	char		*miscname;
357*0Sstevel@tonic-gate 	int		c;
358*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
359*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
360*0Sstevel@tonic-gate 	int		error;
361*0Sstevel@tonic-gate 	bool_t		called_thru_rpc = FALSE;
362*0Sstevel@tonic-gate 	char		*cp;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	/*
365*0Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
366*0Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
367*0Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
368*0Sstevel@tonic-gate 	 * something.
369*0Sstevel@tonic-gate 	 */
370*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
371*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
372*0Sstevel@tonic-gate #endif
373*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
374*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	/* initialize */
377*0Sstevel@tonic-gate 	if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
378*0Sstevel@tonic-gate 		if (sdssc_bind_library() == SDSSC_OKAY)
379*0Sstevel@tonic-gate 			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
380*0Sstevel@tonic-gate 						&error) == SDSSC_PROXY_DONE)
381*0Sstevel@tonic-gate 				exit(error);
382*0Sstevel@tonic-gate 	} else {
383*0Sstevel@tonic-gate 		*cp = '\0'; /* cut off ".rpc_call" */
384*0Sstevel@tonic-gate 		called_thru_rpc = TRUE;
385*0Sstevel@tonic-gate 	}
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0 ||
388*0Sstevel@tonic-gate 			meta_check_root(ep) != 0) {
389*0Sstevel@tonic-gate 		mde_perror(ep, "");
390*0Sstevel@tonic-gate 		md_exit(sp, 1);
391*0Sstevel@tonic-gate 	}
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	/* find set and metadevice first */
394*0Sstevel@tonic-gate 	optind = 1;
395*0Sstevel@tonic-gate 	opterr = 1;
396*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "hns:A:ai:?")) != -1) {
397*0Sstevel@tonic-gate 		switch (c) {
398*0Sstevel@tonic-gate 		case 'h':
399*0Sstevel@tonic-gate 			usage(sp, 0);
400*0Sstevel@tonic-gate 			break;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 		case 'n':
403*0Sstevel@tonic-gate 			if (called_thru_rpc == TRUE) {
404*0Sstevel@tonic-gate 				options &= ~MDCMD_DOIT;
405*0Sstevel@tonic-gate 			} else {
406*0Sstevel@tonic-gate 				usage(sp, 1);
407*0Sstevel@tonic-gate 			}
408*0Sstevel@tonic-gate 			break;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		case 's':
411*0Sstevel@tonic-gate 			sname = optarg;
412*0Sstevel@tonic-gate 			break;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		case '?':
415*0Sstevel@tonic-gate 			if (optopt == '?')
416*0Sstevel@tonic-gate 				usage(sp, 0);
417*0Sstevel@tonic-gate 			break;
418*0Sstevel@tonic-gate 		}
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 	if ((argc - optind) <= 0)
421*0Sstevel@tonic-gate 		usage(sp, 1);
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	if (sname != NULL) {
424*0Sstevel@tonic-gate 		if ((sp = metasetname(sname, ep)) == NULL) {
425*0Sstevel@tonic-gate 			mde_perror(ep, "");
426*0Sstevel@tonic-gate 			md_exit(sp, 1);
427*0Sstevel@tonic-gate 		}
428*0Sstevel@tonic-gate 	}
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	if (((np = metaname(&sp, argv[optind], ep)) == NULL) ||
431*0Sstevel@tonic-gate 	    (metachkmeta(np, ep) != 0)) {
432*0Sstevel@tonic-gate 		mde_perror(ep, "");
433*0Sstevel@tonic-gate 		md_exit(sp, 1);
434*0Sstevel@tonic-gate 	}
435*0Sstevel@tonic-gate 	assert(sp != NULL);
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if ((called_thru_rpc == FALSE) &&
438*0Sstevel@tonic-gate 	    meta_is_mn_name(&sp, argv[optind], ep)) {
439*0Sstevel@tonic-gate 		/*
440*0Sstevel@tonic-gate 		 * If we are dealing with a MN set and we were not
441*0Sstevel@tonic-gate 		 * called thru an rpc call, we are just to send this
442*0Sstevel@tonic-gate 		 * command string to the master of the set and let it
443*0Sstevel@tonic-gate 		 * deal with it.
444*0Sstevel@tonic-gate 		 * Note that if sp is NULL, meta_is_mn_name() derives sp
445*0Sstevel@tonic-gate 		 * from argv[optind] which is the metadevice arg
446*0Sstevel@tonic-gate 		 */
447*0Sstevel@tonic-gate 		int	i;
448*0Sstevel@tonic-gate 		int	newargc;
449*0Sstevel@tonic-gate 		int	result;
450*0Sstevel@tonic-gate 		char	**newargv;
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 		if ((miscname = metagetmiscname(np, ep)) == NULL) {
453*0Sstevel@tonic-gate 			mde_perror(ep, "");
454*0Sstevel@tonic-gate 			md_exit(sp, 1);
455*0Sstevel@tonic-gate 		}
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 		newargv = calloc(argc+1, sizeof (char *));
458*0Sstevel@tonic-gate 		newargv[0] = "metattach";
459*0Sstevel@tonic-gate 		newargv[1] = "-n"; /* always do "-n" first */
460*0Sstevel@tonic-gate 		newargc = 2;
461*0Sstevel@tonic-gate 		for (i = 1; i < argc; i++, newargc++)
462*0Sstevel@tonic-gate 			newargv[newargc] = argv[i];
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 		result = meta_mn_send_command(sp, newargc, newargv,
465*0Sstevel@tonic-gate 		    MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep);
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 		/* If we found a problem don't do it for real */
468*0Sstevel@tonic-gate 		if (result != 0) {
469*0Sstevel@tonic-gate 			md_exit(sp, result);
470*0Sstevel@tonic-gate 		}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 		/*
473*0Sstevel@tonic-gate 		 * Do it for real now. Remove "-n" from the arguments and
474*0Sstevel@tonic-gate 		 * MD_DRYRUN from the flags. If we fail now, the master must
475*0Sstevel@tonic-gate 		 * panic as the mddbs may be inconsistent.
476*0Sstevel@tonic-gate 		 */
477*0Sstevel@tonic-gate 		newargv[1] = ""; /* this was "-n" before */
478*0Sstevel@tonic-gate 		result = meta_mn_send_command(sp, newargc, newargv,
479*0Sstevel@tonic-gate 		    MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
480*0Sstevel@tonic-gate 		    NO_CONTEXT_STRING, ep);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 		free(newargv);
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 		/*
485*0Sstevel@tonic-gate 		 * If the metattach command succeeds, for a mirror, send a
486*0Sstevel@tonic-gate 		 * resync starting message for the metadevice
487*0Sstevel@tonic-gate 		 */
488*0Sstevel@tonic-gate 		if ((result == 0) && (strcmp(miscname, MD_MIRROR) == 0))
489*0Sstevel@tonic-gate 			if ((result = meta_mn_send_resync_starting(np, ep))
490*0Sstevel@tonic-gate 			    != 0)
491*0Sstevel@tonic-gate 				mde_perror(ep, "Unable to start resync");
492*0Sstevel@tonic-gate 		md_exit(sp, result);
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, ep)) {
496*0Sstevel@tonic-gate 		mde_perror(ep, "");
497*0Sstevel@tonic-gate 		md_exit(sp, 1);
498*0Sstevel@tonic-gate 	}
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) != 0) {
501*0Sstevel@tonic-gate 		mde_perror(ep, "");
502*0Sstevel@tonic-gate 		md_exit(sp, 1);
503*0Sstevel@tonic-gate 	}
504*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(np, ep)) == NULL) {
505*0Sstevel@tonic-gate 		mde_perror(ep, "");
506*0Sstevel@tonic-gate 		md_exit(sp, 1);
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	/* dispatch based on device type */
510*0Sstevel@tonic-gate 	if (strcmp(miscname, MD_STRIPE) == 0) {
511*0Sstevel@tonic-gate 		if (stripe_attach(&sp, np, argc, argv, options, ep) != 0) {
512*0Sstevel@tonic-gate 			mde_perror(ep, "");
513*0Sstevel@tonic-gate 			md_exit(sp, 1);
514*0Sstevel@tonic-gate 		}
515*0Sstevel@tonic-gate 	} else if (strcmp(miscname, MD_RAID) == 0) {
516*0Sstevel@tonic-gate 		if (raid_attach(&sp, np, argc, argv, options, ep) != 0) {
517*0Sstevel@tonic-gate 			mde_perror(ep, "");
518*0Sstevel@tonic-gate 			md_exit(sp, 1);
519*0Sstevel@tonic-gate 		}
520*0Sstevel@tonic-gate 	} else if (strcmp(miscname, MD_MIRROR) == 0) {
521*0Sstevel@tonic-gate 		if (mirror_attach(&sp, np, argc, argv, options, ep) != 0) {
522*0Sstevel@tonic-gate 			mde_perror(ep, "");
523*0Sstevel@tonic-gate 			md_exit(sp, 1);
524*0Sstevel@tonic-gate 		}
525*0Sstevel@tonic-gate 	} else if (strcmp(miscname, MD_TRANS) == 0) {
526*0Sstevel@tonic-gate 		md_eprintf(gettext(MD_EOF_TRANS_MSG));
527*0Sstevel@tonic-gate 		md_exit(sp, 1);
528*0Sstevel@tonic-gate 	} else if (strcmp(miscname, MD_SP) == 0) {
529*0Sstevel@tonic-gate 		if (sp_attach(&sp, np, argc, argv, options, ep) != 0) {
530*0Sstevel@tonic-gate 			mde_perror(ep, "");
531*0Sstevel@tonic-gate 			md_exit(sp, 1);
532*0Sstevel@tonic-gate 		}
533*0Sstevel@tonic-gate 	} else {
534*0Sstevel@tonic-gate 		md_eprintf(gettext(
535*0Sstevel@tonic-gate 		    "%s: invalid metadevice type %s\n"),
536*0Sstevel@tonic-gate 		    np->cname, miscname);
537*0Sstevel@tonic-gate 		md_exit(sp, 1);
538*0Sstevel@tonic-gate 	}
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	/* return success */
541*0Sstevel@tonic-gate 	md_exit(sp, 0);
542*0Sstevel@tonic-gate 	/*NOTREACHED*/
543*0Sstevel@tonic-gate 	return (0);
544*0Sstevel@tonic-gate }
545