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 1992-2003 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  * patch system files for root on metadevice
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <meta.h>
34*0Sstevel@tonic-gate #include <stdlib.h>
35*0Sstevel@tonic-gate #include <sdssc.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #define	METAROOT_OK 0
38*0Sstevel@tonic-gate #define	METAROOT_ERR -1
39*0Sstevel@tonic-gate #define	METAROOT_NOTFOUND -2
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate struct def_map {
42*0Sstevel@tonic-gate 	char		**dm_fname;	/* Location of file name */
43*0Sstevel@tonic-gate 	char		*dm_default;	/* Default name */
44*0Sstevel@tonic-gate };
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /*
47*0Sstevel@tonic-gate  * options
48*0Sstevel@tonic-gate  */
49*0Sstevel@tonic-gate static	char	*cname = NULL;	/* take default */
50*0Sstevel@tonic-gate static	char	*sname = NULL;	/* take default */
51*0Sstevel@tonic-gate static	char	*vname = NULL;	/* take default */
52*0Sstevel@tonic-gate static	char	*dbname = NULL;	/* take default bootlist location */
53*0Sstevel@tonic-gate static	int	doit = 1;
54*0Sstevel@tonic-gate static	int	verbose = 0;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate  * Map of default system file names to the place where they are stored.
58*0Sstevel@tonic-gate  * This is used if the -R option is specified.  Note that the members of
59*0Sstevel@tonic-gate  * the map point to the cname, sname, vname and dbname global variables
60*0Sstevel@tonic-gate  * above.  These global variables are used in the call to
61*0Sstevel@tonic-gate  * meta_patch_rootdev() in main().
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate static struct def_map	default_names[] = {
64*0Sstevel@tonic-gate 	&cname, META_DBCONF,
65*0Sstevel@tonic-gate 	&sname, "/etc/system",
66*0Sstevel@tonic-gate 	&vname, "/etc/vfstab",
67*0Sstevel@tonic-gate 	&dbname, "/kernel/drv/md.conf"
68*0Sstevel@tonic-gate };
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate static int validate_stripe_root();
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * print usage message, md_exit
74*0Sstevel@tonic-gate  */
75*0Sstevel@tonic-gate static void
76*0Sstevel@tonic-gate usage(
77*0Sstevel@tonic-gate 	mdsetname_t	*sp,
78*0Sstevel@tonic-gate 	int		eval
79*0Sstevel@tonic-gate )
80*0Sstevel@tonic-gate {
81*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\
82*0Sstevel@tonic-gate usage:\t%s [-n] [-k system-name] [-m md.conf-name] [-v vfstab-name] \\\n\
83*0Sstevel@tonic-gate \t\t[-c mddb.cf-name] device\n\
84*0Sstevel@tonic-gate \t%s [-n] [-R root-path] device\n"),
85*0Sstevel@tonic-gate 	    myname, myname);
86*0Sstevel@tonic-gate 	md_exit(sp, eval);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static void
90*0Sstevel@tonic-gate free_mem()
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	int			i;
93*0Sstevel@tonic-gate 	struct def_map		*map;
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 	for (i = 0, map = default_names;
96*0Sstevel@tonic-gate 		i < sizeof (default_names) / sizeof (struct def_map);
97*0Sstevel@tonic-gate 		i++, map++) {
98*0Sstevel@tonic-gate 		if (*map->dm_fname != NULL) {
99*0Sstevel@tonic-gate 			free((void *) *map->dm_fname);
100*0Sstevel@tonic-gate 			*map->dm_fname = NULL;
101*0Sstevel@tonic-gate 		}
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate }
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate /*
106*0Sstevel@tonic-gate  * Check if mirror, mirnp, is a valid root filesystem, ie all
107*0Sstevel@tonic-gate  * submirrors must be single disk stripe, and that the slice, slicenp,
108*0Sstevel@tonic-gate  * if not NULL, is a component of one of the submirrors.
109*0Sstevel@tonic-gate  * The arg metaroot is TRUE if mirnp is the current root filesystem.
110*0Sstevel@tonic-gate  * Returns:
111*0Sstevel@tonic-gate  * METAROOT_OK		if mirror is valid and slicenp is a component
112*0Sstevel@tonic-gate  * METAROOT_NOTFOUND	if mirror valid but slicenp not a component
113*0Sstevel@tonic-gate  * METAROOT_ERR		if mirror not a valid root
114*0Sstevel@tonic-gate  */
115*0Sstevel@tonic-gate static int
116*0Sstevel@tonic-gate validate_mirror_root(
117*0Sstevel@tonic-gate 	mdsetname_t	*sp,
118*0Sstevel@tonic-gate 	mdname_t	*mirnp,
119*0Sstevel@tonic-gate 	mdname_t	*slicenp,
120*0Sstevel@tonic-gate 	int		metaroot,
121*0Sstevel@tonic-gate 	md_error_t	*ep
122*0Sstevel@tonic-gate )
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	int 		smi;
125*0Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
126*0Sstevel@tonic-gate 	char		*miscname;
127*0Sstevel@tonic-gate 	int		found = 0;
128*0Sstevel@tonic-gate 	int		rval;
129*0Sstevel@tonic-gate 	int		err = 0;
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL) {
132*0Sstevel@tonic-gate 		mde_perror(ep, "");
133*0Sstevel@tonic-gate 		return (METAROOT_ERR);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
137*0Sstevel@tonic-gate 		/* Check all submirrors */
138*0Sstevel@tonic-gate 		md_submirror_t  *mdsp = &mirrorp->submirrors[smi];
139*0Sstevel@tonic-gate 		mdname_t	*submirnamep = mdsp->submirnamep;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 		/* skip unused submirrors */
142*0Sstevel@tonic-gate 		if (submirnamep == NULL) {
143*0Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
144*0Sstevel@tonic-gate 			continue;
145*0Sstevel@tonic-gate 		}
146*0Sstevel@tonic-gate 		if ((miscname = metagetmiscname(submirnamep, ep)) == NULL) {
147*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_UNKNOWN_TYPE,
148*0Sstevel@tonic-gate 					meta_getminor(submirnamep->dev),
149*0Sstevel@tonic-gate 					submirnamep->cname));
150*0Sstevel@tonic-gate 		}
151*0Sstevel@tonic-gate 		if (strcmp(miscname, MD_STRIPE) != 0) {
152*0Sstevel@tonic-gate 			md_eprintf(gettext("Submirror is not a stripe\n"));
153*0Sstevel@tonic-gate 			return (METAROOT_ERR);
154*0Sstevel@tonic-gate 		}
155*0Sstevel@tonic-gate 		rval = validate_stripe_root(sp, submirnamep, slicenp,
156*0Sstevel@tonic-gate 		    metaroot, ep);
157*0Sstevel@tonic-gate 		switch (rval) {
158*0Sstevel@tonic-gate 		case METAROOT_OK:
159*0Sstevel@tonic-gate 			found = 1;
160*0Sstevel@tonic-gate 			break;
161*0Sstevel@tonic-gate 		case METAROOT_ERR:
162*0Sstevel@tonic-gate 			err++;
163*0Sstevel@tonic-gate 			break;
164*0Sstevel@tonic-gate 		case METAROOT_NOTFOUND:
165*0Sstevel@tonic-gate 		default:
166*0Sstevel@tonic-gate 			break;
167*0Sstevel@tonic-gate 		}
168*0Sstevel@tonic-gate 	}
169*0Sstevel@tonic-gate 	if (err > 0)
170*0Sstevel@tonic-gate 		return (METAROOT_ERR);
171*0Sstevel@tonic-gate 	if (!found)
172*0Sstevel@tonic-gate 		return (METAROOT_NOTFOUND);
173*0Sstevel@tonic-gate 	return (METAROOT_OK);
174*0Sstevel@tonic-gate }
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate /*
177*0Sstevel@tonic-gate  * Check if stripe, strnp, is a valid root filesystem, ie must
178*0Sstevel@tonic-gate  * be single disk stripe, and the the slice, slicenp, if not NULL, must
179*0Sstevel@tonic-gate  * be a component of this stripe.
180*0Sstevel@tonic-gate  * The arg metaroot is TRUE if strnp is the current root filesystem.
181*0Sstevel@tonic-gate  * Returns:
182*0Sstevel@tonic-gate  * METAROOT_OK		if stripe is valid and slicenp is a component
183*0Sstevel@tonic-gate  * METAROOT_NOTFOUND	if stripe valid but slicenp not a component
184*0Sstevel@tonic-gate  * METAROOT_ERR		if stripe not a valid root
185*0Sstevel@tonic-gate  */
186*0Sstevel@tonic-gate static int
187*0Sstevel@tonic-gate validate_stripe_root(
188*0Sstevel@tonic-gate 	mdsetname_t	*sp,
189*0Sstevel@tonic-gate 	mdname_t	*strnp,
190*0Sstevel@tonic-gate 	mdname_t	*slicenp,
191*0Sstevel@tonic-gate 	int		metaroot,
192*0Sstevel@tonic-gate 	md_error_t	*ep
193*0Sstevel@tonic-gate )
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
196*0Sstevel@tonic-gate 	md_row_t	*rp;
197*0Sstevel@tonic-gate 	md_comp_t	*cp;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe(sp, strnp, ep)) == NULL) {
200*0Sstevel@tonic-gate 		mde_perror(ep, "");
201*0Sstevel@tonic-gate 		return (METAROOT_ERR);
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 	if (stripep->rows.rows_len != 1) {
204*0Sstevel@tonic-gate 		md_eprintf(gettext(
205*0Sstevel@tonic-gate 		    "Concat %s has more than 1 slice\n"), strnp->cname);
206*0Sstevel@tonic-gate 		return (METAROOT_ERR);
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 	rp = &stripep->rows.rows_val[0];
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	if (rp->comps.comps_len != 1) {
211*0Sstevel@tonic-gate 		md_eprintf(gettext(
212*0Sstevel@tonic-gate 		    "Stripe %s has more than 1 slice\n"), strnp->cname);
213*0Sstevel@tonic-gate 		return (METAROOT_ERR);
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 	cp = &rp->comps.comps_val[0];
216*0Sstevel@tonic-gate 	if (!metaismeta(cp->compnamep)) {
217*0Sstevel@tonic-gate 		if (slicenp == NULL)
218*0Sstevel@tonic-gate 			return (METAROOT_OK);
219*0Sstevel@tonic-gate 		if (strcmp(slicenp->cname, cp->compnamep->cname) == 0)
220*0Sstevel@tonic-gate 			return (METAROOT_OK);
221*0Sstevel@tonic-gate 		if (!metaroot) {
222*0Sstevel@tonic-gate 			md_eprintf(gettext(
223*0Sstevel@tonic-gate 			    "Root %s is not a component of metadevice %s\n"),
224*0Sstevel@tonic-gate 			    slicenp->cname, strnp->cname);
225*0Sstevel@tonic-gate 		}
226*0Sstevel@tonic-gate 		return (METAROOT_NOTFOUND);
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 	md_eprintf(gettext(
229*0Sstevel@tonic-gate 	    "Component %s is not a stripe\n"), cp->compnamep->cname);
230*0Sstevel@tonic-gate 	return (METAROOT_ERR);
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate /*
234*0Sstevel@tonic-gate  * Check if the device devnp is valid. It must be a component of the
235*0Sstevel@tonic-gate  * metadevice that contains the root filesystem
236*0Sstevel@tonic-gate  */
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate static int
239*0Sstevel@tonic-gate validate_root_device(
240*0Sstevel@tonic-gate 	mdsetname_t	*sp,
241*0Sstevel@tonic-gate 	mdname_t	*devnp,
242*0Sstevel@tonic-gate 	md_error_t	*ep
243*0Sstevel@tonic-gate )
244*0Sstevel@tonic-gate {
245*0Sstevel@tonic-gate 	mdname_t	*rootnp;
246*0Sstevel@tonic-gate 	char		*curroot;
247*0Sstevel@tonic-gate 	char		*miscname;
248*0Sstevel@tonic-gate 	int		rval;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if ((curroot = meta_get_current_root(ep)) == NULL) {
251*0Sstevel@tonic-gate 		mde_perror(ep, "");
252*0Sstevel@tonic-gate 		return (METAROOT_ERR);
253*0Sstevel@tonic-gate 	}
254*0Sstevel@tonic-gate 	if ((rootnp = metaname(&sp, curroot, ep)) == NULL) {
255*0Sstevel@tonic-gate 		mde_perror(ep, "");
256*0Sstevel@tonic-gate 		return (METAROOT_ERR);
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	if (metaismeta(rootnp)) {
260*0Sstevel@tonic-gate 		/* get type */
261*0Sstevel@tonic-gate 		if ((miscname = metagetmiscname(rootnp, ep)) == NULL) {
262*0Sstevel@tonic-gate 			mde_perror(ep, "");
263*0Sstevel@tonic-gate 			return (METAROOT_ERR);
264*0Sstevel@tonic-gate 		}
265*0Sstevel@tonic-gate 		if (strcmp(miscname, MD_MIRROR) == 0) {
266*0Sstevel@tonic-gate 			if ((rval = validate_mirror_root(sp, rootnp,
267*0Sstevel@tonic-gate 			    devnp, 1, ep)) == METAROOT_OK)
268*0Sstevel@tonic-gate 				return (METAROOT_OK);
269*0Sstevel@tonic-gate 			if (rval == METAROOT_NOTFOUND) {
270*0Sstevel@tonic-gate 				md_eprintf(gettext(
271*0Sstevel@tonic-gate 				    "Slice %s is not a component of root %s\n"),
272*0Sstevel@tonic-gate 				    devnp->cname, rootnp->cname);
273*0Sstevel@tonic-gate 			}
274*0Sstevel@tonic-gate 			return (METAROOT_ERR);
275*0Sstevel@tonic-gate 		} else if (strcmp(miscname, MD_STRIPE) == 0) {
276*0Sstevel@tonic-gate 			if ((rval = validate_stripe_root(sp, rootnp,
277*0Sstevel@tonic-gate 			    devnp, 1, ep)) == METAROOT_OK)
278*0Sstevel@tonic-gate 				return (METAROOT_OK);
279*0Sstevel@tonic-gate 			if (rval == METAROOT_NOTFOUND) {
280*0Sstevel@tonic-gate 				md_eprintf(gettext(
281*0Sstevel@tonic-gate 				    "Slice %s is not a component of root %s\n"),
282*0Sstevel@tonic-gate 				    devnp->cname, rootnp->cname);
283*0Sstevel@tonic-gate 			}
284*0Sstevel@tonic-gate 			return (METAROOT_ERR);
285*0Sstevel@tonic-gate 		} else {
286*0Sstevel@tonic-gate 			md_eprintf(gettext(
287*0Sstevel@tonic-gate 			    "Root metadevice, %s, is not a Slice or Mirror\n"),
288*0Sstevel@tonic-gate 			    rootnp->cname);
289*0Sstevel@tonic-gate 			return (METAROOT_ERR);
290*0Sstevel@tonic-gate 		}
291*0Sstevel@tonic-gate 	} else {
292*0Sstevel@tonic-gate 		md_eprintf(gettext(
293*0Sstevel@tonic-gate 		    "Current Root %s is not a metadevice\n"), rootnp->cname);
294*0Sstevel@tonic-gate 		return (METAROOT_ERR);
295*0Sstevel@tonic-gate 	}
296*0Sstevel@tonic-gate }
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate /*
299*0Sstevel@tonic-gate  * What we're going to do:
300*0Sstevel@tonic-gate  *
301*0Sstevel@tonic-gate  * 1) Check if the device is a metadevice or not.
302*0Sstevel@tonic-gate  *
303*0Sstevel@tonic-gate  * 2) If a metadevice, and it is valid, ie a stripe or a mirror containing
304*0Sstevel@tonic-gate  *    a single slice, add "forceload:{drv,misc}/<modname>" of
305*0Sstevel@tonic-gate  *    underlying drivers for the meta-root and the metadevice
306*0Sstevel@tonic-gate  *    database to system. Otherwise, remove forceloads from system if the
307*0Sstevel@tonic-gate  *    slice is a component of the current root metadevice.
308*0Sstevel@tonic-gate  *
309*0Sstevel@tonic-gate  * 3) Add "rootdev:/devices/..." to system.
310*0Sstevel@tonic-gate  *
311*0Sstevel@tonic-gate  * 4) Replace / mount in vfstab.
312*0Sstevel@tonic-gate  *
313*0Sstevel@tonic-gate  * 5) Repatch database locations, just to be safe.
314*0Sstevel@tonic-gate  */
315*0Sstevel@tonic-gate int
316*0Sstevel@tonic-gate main(
317*0Sstevel@tonic-gate 	int		argc,
318*0Sstevel@tonic-gate 	char		*argv[]
319*0Sstevel@tonic-gate )
320*0Sstevel@tonic-gate {
321*0Sstevel@tonic-gate 	int		i;
322*0Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
323*0Sstevel@tonic-gate 	mdname_t	*rootnp;
324*0Sstevel@tonic-gate 	int		c;
325*0Sstevel@tonic-gate 	int		ckmv_flag = 0;	/* non-zero if -c, -k, -m or -v */
326*0Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
327*0Sstevel@tonic-gate 	md_error_t	*ep = &status;
328*0Sstevel@tonic-gate 	char		*miscname;
329*0Sstevel@tonic-gate 	char		*curroot;
330*0Sstevel@tonic-gate 	mdname_t	*currootnp;
331*0Sstevel@tonic-gate 	mdname_t	*currootdevnp;
332*0Sstevel@tonic-gate 	char		*root_path = NULL;
333*0Sstevel@tonic-gate 	struct def_map	*map;
334*0Sstevel@tonic-gate 	size_t		root_path_size;
335*0Sstevel@tonic-gate 	size_t		path_buf_size;
336*0Sstevel@tonic-gate 	int		error;
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	/*
339*0Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
340*0Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
341*0Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
342*0Sstevel@tonic-gate 	 * something.
343*0Sstevel@tonic-gate 	 */
344*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
345*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
346*0Sstevel@tonic-gate #endif
347*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
348*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if ((sdssc_bind_library() == SDSSC_OKAY) &&
351*0Sstevel@tonic-gate 		(sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
352*0Sstevel@tonic-gate 		    &error) == SDSSC_PROXY_DONE))
353*0Sstevel@tonic-gate 			exit(error);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/* initialize */
356*0Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0 ||
357*0Sstevel@tonic-gate 			meta_check_root(ep) != 0) {
358*0Sstevel@tonic-gate 		mde_perror(ep, "");
359*0Sstevel@tonic-gate 		md_exit(sp, 1);
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/* parse options */
363*0Sstevel@tonic-gate 	optind = 1;
364*0Sstevel@tonic-gate 	opterr = 1;
365*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "hnk:m:v:c:R:?")) != -1) {
366*0Sstevel@tonic-gate 		switch (c) {
367*0Sstevel@tonic-gate 		case 'h':
368*0Sstevel@tonic-gate 			usage(sp, 0);
369*0Sstevel@tonic-gate 			break;
370*0Sstevel@tonic-gate 		case 'm':
371*0Sstevel@tonic-gate 			dbname = optarg;
372*0Sstevel@tonic-gate 			ckmv_flag = 1;
373*0Sstevel@tonic-gate 			break;
374*0Sstevel@tonic-gate 		case 'n':
375*0Sstevel@tonic-gate 			doit = 0;
376*0Sstevel@tonic-gate 			verbose = 1;
377*0Sstevel@tonic-gate 			break;
378*0Sstevel@tonic-gate 		case 'k':
379*0Sstevel@tonic-gate 			sname = optarg;
380*0Sstevel@tonic-gate 			ckmv_flag = 1;
381*0Sstevel@tonic-gate 			break;
382*0Sstevel@tonic-gate 		case 'v':
383*0Sstevel@tonic-gate 			vname = optarg;
384*0Sstevel@tonic-gate 			ckmv_flag = 1;
385*0Sstevel@tonic-gate 			break;
386*0Sstevel@tonic-gate 		case 'c':
387*0Sstevel@tonic-gate 			cname = optarg;
388*0Sstevel@tonic-gate 			ckmv_flag = 1;
389*0Sstevel@tonic-gate 			break;
390*0Sstevel@tonic-gate 		case 'R':
391*0Sstevel@tonic-gate 			root_path = optarg;
392*0Sstevel@tonic-gate 			break;
393*0Sstevel@tonic-gate 		case '?':
394*0Sstevel@tonic-gate 			if (optopt == '?')
395*0Sstevel@tonic-gate 				usage(sp, 0);
396*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
397*0Sstevel@tonic-gate 		default:
398*0Sstevel@tonic-gate 			usage(sp, 1);
399*0Sstevel@tonic-gate 			break;
400*0Sstevel@tonic-gate 		}
401*0Sstevel@tonic-gate 	}
402*0Sstevel@tonic-gate 	argc -= optind;
403*0Sstevel@tonic-gate 	argv += optind;
404*0Sstevel@tonic-gate 	if (argc != 1)
405*0Sstevel@tonic-gate 		usage(sp, 1);
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	/* Can't use -R with any of -c, -k, -m or -v */
408*0Sstevel@tonic-gate 	if ((ckmv_flag != 0) && (root_path != NULL)) {
409*0Sstevel@tonic-gate 		md_eprintf(
410*0Sstevel@tonic-gate 			gettext("-R invalid with any of -c, -k, -m or -v\n"));
411*0Sstevel@tonic-gate 		usage(sp, 1);
412*0Sstevel@tonic-gate 	}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/* get device name */
415*0Sstevel@tonic-gate 	if ((rootnp = metaname(&sp, argv[0], ep)) == NULL) {
416*0Sstevel@tonic-gate 		mde_perror(ep, "");
417*0Sstevel@tonic-gate 		md_exit(sp, 1);
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 	if ((curroot = meta_get_current_root(ep)) == NULL) {
420*0Sstevel@tonic-gate 		mde_perror(ep, "");
421*0Sstevel@tonic-gate 		md_exit(sp, 1);
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 	/*
424*0Sstevel@tonic-gate 	 * Get device name of current root metadevice.  If root is net
425*0Sstevel@tonic-gate 	 * mounted as happens if this command is part of the install
426*0Sstevel@tonic-gate 	 * process, currootnp will be set to NULL.
427*0Sstevel@tonic-gate 	 */
428*0Sstevel@tonic-gate 	currootnp = metaname(&sp, curroot, ep);
429*0Sstevel@tonic-gate 	/*
430*0Sstevel@tonic-gate 	 * If the argument is the name of the current root filesystem, then
431*0Sstevel@tonic-gate 	 * the command is allowed, otherwise check that the argument is
432*0Sstevel@tonic-gate 	 * valid.
433*0Sstevel@tonic-gate 	 */
434*0Sstevel@tonic-gate 	if ((currootnp == NULL) ||
435*0Sstevel@tonic-gate 		(strcmp(currootnp->cname, rootnp->cname) != 0)) {
436*0Sstevel@tonic-gate 		if (metaismeta(rootnp)) {
437*0Sstevel@tonic-gate 			/*
438*0Sstevel@tonic-gate 			 * Validate that the metadevice is based on a
439*0Sstevel@tonic-gate 			 * single slice. If none of the -k, -m, -v, -c or
440*0Sstevel@tonic-gate 			 * -R options are specified, then the default
441*0Sstevel@tonic-gate 			 * system files are being modified and hence the
442*0Sstevel@tonic-gate 			 * current root slice must be a component of the
443*0Sstevel@tonic-gate 			 * metadevice. If any of the previously mentioned
444*0Sstevel@tonic-gate 			 * options are used don't check that the current
445*0Sstevel@tonic-gate 			 * root is a component.
446*0Sstevel@tonic-gate 			 */
447*0Sstevel@tonic-gate 			if ((ckmv_flag == 0) && (root_path == NULL)) {
448*0Sstevel@tonic-gate 				/* Get device name of current root slice */
449*0Sstevel@tonic-gate 				if ((currootdevnp =
450*0Sstevel@tonic-gate 				    meta_get_current_root_dev(sp, ep))
451*0Sstevel@tonic-gate 				    == NULL) {
452*0Sstevel@tonic-gate 					mde_perror(ep, "");
453*0Sstevel@tonic-gate 					md_exit(sp, 1);
454*0Sstevel@tonic-gate 				}
455*0Sstevel@tonic-gate 			} else currootdevnp = NULL;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 			if ((miscname = metagetmiscname(rootnp, ep)) == NULL) {
458*0Sstevel@tonic-gate 				mde_perror(ep, "");
459*0Sstevel@tonic-gate 				md_exit(sp, 1);
460*0Sstevel@tonic-gate 			}
461*0Sstevel@tonic-gate 			/* Check that metadevice is a mirror or a stripe */
462*0Sstevel@tonic-gate 			if (strcmp(miscname, MD_MIRROR) == 0) {
463*0Sstevel@tonic-gate 				if (validate_mirror_root(sp, rootnp,
464*0Sstevel@tonic-gate 				    currootdevnp, 0, ep) != METAROOT_OK) {
465*0Sstevel@tonic-gate 					md_exit(sp, 1);
466*0Sstevel@tonic-gate 				}
467*0Sstevel@tonic-gate 			} else if (strcmp(miscname, MD_STRIPE) == 0) {
468*0Sstevel@tonic-gate 				if (validate_stripe_root(sp, rootnp,
469*0Sstevel@tonic-gate 				    currootdevnp, 0, ep) != METAROOT_OK) {
470*0Sstevel@tonic-gate 					md_exit(sp, 1);
471*0Sstevel@tonic-gate 				}
472*0Sstevel@tonic-gate 			} else {
473*0Sstevel@tonic-gate 				md_eprintf(gettext(
474*0Sstevel@tonic-gate 				    "%s is not a mirror or stripe\n"),
475*0Sstevel@tonic-gate 				    rootnp->cname);
476*0Sstevel@tonic-gate 				md_exit(sp, 1);
477*0Sstevel@tonic-gate 			}
478*0Sstevel@tonic-gate 		} else {
479*0Sstevel@tonic-gate 			/*
480*0Sstevel@tonic-gate 			 * Check that the root device is a component of the
481*0Sstevel@tonic-gate 			 * current root filesystem only if the default system
482*0Sstevel@tonic-gate 			 * files are being modified
483*0Sstevel@tonic-gate 			 */
484*0Sstevel@tonic-gate 			if ((ckmv_flag == 0) && (root_path == NULL)) {
485*0Sstevel@tonic-gate 				if (validate_root_device(sp, rootnp, ep) != 0) {
486*0Sstevel@tonic-gate 					md_exit(sp, 1);
487*0Sstevel@tonic-gate 				}
488*0Sstevel@tonic-gate 			}
489*0Sstevel@tonic-gate 		}
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, ep)) {
493*0Sstevel@tonic-gate 		mde_perror(ep, "");
494*0Sstevel@tonic-gate 		md_exit(sp, 1);
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	/*
498*0Sstevel@tonic-gate 	 * If -R is specified, use the default system file names relative
499*0Sstevel@tonic-gate 	 * to the new root location.
500*0Sstevel@tonic-gate 	 */
501*0Sstevel@tonic-gate 	if (root_path != NULL) {
502*0Sstevel@tonic-gate 		root_path_size = strlen(root_path);
503*0Sstevel@tonic-gate 		for (i = 0, map = default_names;
504*0Sstevel@tonic-gate 			i < sizeof (default_names) / sizeof (struct def_map);
505*0Sstevel@tonic-gate 			i++, map++) {
506*0Sstevel@tonic-gate 			/* Add 1 for null terminator */
507*0Sstevel@tonic-gate 			path_buf_size = root_path_size +
508*0Sstevel@tonic-gate 				strlen(map->dm_default) + 1;
509*0Sstevel@tonic-gate 			*map->dm_fname = malloc(path_buf_size);
510*0Sstevel@tonic-gate 			if (*map->dm_fname == NULL) {
511*0Sstevel@tonic-gate 				md_eprintf(gettext("Cannot allocate memory \
512*0Sstevel@tonic-gate for system file path relocation\n"));
513*0Sstevel@tonic-gate 				md_exit(sp, 1);
514*0Sstevel@tonic-gate 			}
515*0Sstevel@tonic-gate 			(void) snprintf(*map->dm_fname, path_buf_size,
516*0Sstevel@tonic-gate 					"%s%s", root_path, map->dm_default);
517*0Sstevel@tonic-gate 		}
518*0Sstevel@tonic-gate 	}
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	/* patch system and vfstab for root and mddb locations */
521*0Sstevel@tonic-gate 	if (meta_patch_rootdev(rootnp, sname, vname, cname, dbname, doit,
522*0Sstevel@tonic-gate 	    verbose, ep) != 0) {
523*0Sstevel@tonic-gate 		if (root_path != NULL) {
524*0Sstevel@tonic-gate 			free_mem();
525*0Sstevel@tonic-gate 		}
526*0Sstevel@tonic-gate 		mde_perror(ep, "");
527*0Sstevel@tonic-gate 		md_exit(sp, 1);
528*0Sstevel@tonic-gate 	}
529*0Sstevel@tonic-gate 	if (root_path != NULL) {
530*0Sstevel@tonic-gate 		free_mem();
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	/* return success */
534*0Sstevel@tonic-gate 	md_exit(sp, 0);
535*0Sstevel@tonic-gate 	/*NOTREACHED*/
536*0Sstevel@tonic-gate 	return (0);
537*0Sstevel@tonic-gate }
538