xref: /onnv-gate/usr/src/cmd/lvm/util/metaroot.c (revision 1623:7bac4a816ebe)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1623Stw21770  * Common Development and Distribution License (the "License").
6*1623Stw21770  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*1623Stw21770  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * patch system files for root on metadevice
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <meta.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <sdssc.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #define	METAROOT_OK 0
370Sstevel@tonic-gate #define	METAROOT_ERR -1
380Sstevel@tonic-gate #define	METAROOT_NOTFOUND -2
390Sstevel@tonic-gate 
400Sstevel@tonic-gate struct def_map {
410Sstevel@tonic-gate 	char		**dm_fname;	/* Location of file name */
420Sstevel@tonic-gate 	char		*dm_default;	/* Default name */
430Sstevel@tonic-gate };
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * options
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate static	char	*cname = NULL;	/* take default */
490Sstevel@tonic-gate static	char	*sname = NULL;	/* take default */
500Sstevel@tonic-gate static	char	*vname = NULL;	/* take default */
510Sstevel@tonic-gate static	char	*dbname = NULL;	/* take default bootlist location */
520Sstevel@tonic-gate static	int	doit = 1;
530Sstevel@tonic-gate static	int	verbose = 0;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * Map of default system file names to the place where they are stored.
570Sstevel@tonic-gate  * This is used if the -R option is specified.  Note that the members of
580Sstevel@tonic-gate  * the map point to the cname, sname, vname and dbname global variables
590Sstevel@tonic-gate  * above.  These global variables are used in the call to
600Sstevel@tonic-gate  * meta_patch_rootdev() in main().
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate static struct def_map	default_names[] = {
630Sstevel@tonic-gate 	&cname, META_DBCONF,
640Sstevel@tonic-gate 	&sname, "/etc/system",
650Sstevel@tonic-gate 	&vname, "/etc/vfstab",
660Sstevel@tonic-gate 	&dbname, "/kernel/drv/md.conf"
670Sstevel@tonic-gate };
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static int validate_stripe_root();
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * print usage message, md_exit
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate static void
usage(mdsetname_t * sp,int eval)750Sstevel@tonic-gate usage(
760Sstevel@tonic-gate 	mdsetname_t	*sp,
770Sstevel@tonic-gate 	int		eval
780Sstevel@tonic-gate )
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\
810Sstevel@tonic-gate usage:\t%s [-n] [-k system-name] [-m md.conf-name] [-v vfstab-name] \\\n\
820Sstevel@tonic-gate \t\t[-c mddb.cf-name] device\n\
830Sstevel@tonic-gate \t%s [-n] [-R root-path] device\n"),
840Sstevel@tonic-gate 	    myname, myname);
850Sstevel@tonic-gate 	md_exit(sp, eval);
860Sstevel@tonic-gate }
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static void
free_mem()890Sstevel@tonic-gate free_mem()
900Sstevel@tonic-gate {
910Sstevel@tonic-gate 	int			i;
920Sstevel@tonic-gate 	struct def_map		*map;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	for (i = 0, map = default_names;
950Sstevel@tonic-gate 		i < sizeof (default_names) / sizeof (struct def_map);
960Sstevel@tonic-gate 		i++, map++) {
970Sstevel@tonic-gate 		if (*map->dm_fname != NULL) {
980Sstevel@tonic-gate 			free((void *) *map->dm_fname);
990Sstevel@tonic-gate 			*map->dm_fname = NULL;
1000Sstevel@tonic-gate 		}
1010Sstevel@tonic-gate 	}
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * Check if mirror, mirnp, is a valid root filesystem, ie all
1060Sstevel@tonic-gate  * submirrors must be single disk stripe, and that the slice, slicenp,
1070Sstevel@tonic-gate  * if not NULL, is a component of one of the submirrors.
1080Sstevel@tonic-gate  * The arg metaroot is TRUE if mirnp is the current root filesystem.
1090Sstevel@tonic-gate  * Returns:
1100Sstevel@tonic-gate  * METAROOT_OK		if mirror is valid and slicenp is a component
1110Sstevel@tonic-gate  * METAROOT_NOTFOUND	if mirror valid but slicenp not a component
1120Sstevel@tonic-gate  * METAROOT_ERR		if mirror not a valid root
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate static int
validate_mirror_root(mdsetname_t * sp,mdname_t * mirnp,mdname_t * slicenp,int metaroot,md_error_t * ep)1150Sstevel@tonic-gate validate_mirror_root(
1160Sstevel@tonic-gate 	mdsetname_t	*sp,
1170Sstevel@tonic-gate 	mdname_t	*mirnp,
1180Sstevel@tonic-gate 	mdname_t	*slicenp,
1190Sstevel@tonic-gate 	int		metaroot,
1200Sstevel@tonic-gate 	md_error_t	*ep
1210Sstevel@tonic-gate )
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate 	int 		smi;
1240Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
1250Sstevel@tonic-gate 	char		*miscname;
1260Sstevel@tonic-gate 	int		found = 0;
1270Sstevel@tonic-gate 	int		rval;
1280Sstevel@tonic-gate 	int		err = 0;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL) {
1310Sstevel@tonic-gate 		mde_perror(ep, "");
1320Sstevel@tonic-gate 		return (METAROOT_ERR);
1330Sstevel@tonic-gate 	}
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
1360Sstevel@tonic-gate 		/* Check all submirrors */
1370Sstevel@tonic-gate 		md_submirror_t  *mdsp = &mirrorp->submirrors[smi];
1380Sstevel@tonic-gate 		mdname_t	*submirnamep = mdsp->submirnamep;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		/* skip unused submirrors */
1410Sstevel@tonic-gate 		if (submirnamep == NULL) {
1420Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
1430Sstevel@tonic-gate 			continue;
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 		if ((miscname = metagetmiscname(submirnamep, ep)) == NULL) {
1460Sstevel@tonic-gate 			return (mdmderror(ep, MDE_UNKNOWN_TYPE,
1470Sstevel@tonic-gate 					meta_getminor(submirnamep->dev),
1480Sstevel@tonic-gate 					submirnamep->cname));
1490Sstevel@tonic-gate 		}
1500Sstevel@tonic-gate 		if (strcmp(miscname, MD_STRIPE) != 0) {
1510Sstevel@tonic-gate 			md_eprintf(gettext("Submirror is not a stripe\n"));
1520Sstevel@tonic-gate 			return (METAROOT_ERR);
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 		rval = validate_stripe_root(sp, submirnamep, slicenp,
1550Sstevel@tonic-gate 		    metaroot, ep);
1560Sstevel@tonic-gate 		switch (rval) {
1570Sstevel@tonic-gate 		case METAROOT_OK:
1580Sstevel@tonic-gate 			found = 1;
1590Sstevel@tonic-gate 			break;
1600Sstevel@tonic-gate 		case METAROOT_ERR:
1610Sstevel@tonic-gate 			err++;
1620Sstevel@tonic-gate 			break;
1630Sstevel@tonic-gate 		case METAROOT_NOTFOUND:
1640Sstevel@tonic-gate 		default:
1650Sstevel@tonic-gate 			break;
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 	if (err > 0)
1690Sstevel@tonic-gate 		return (METAROOT_ERR);
1700Sstevel@tonic-gate 	if (!found)
1710Sstevel@tonic-gate 		return (METAROOT_NOTFOUND);
1720Sstevel@tonic-gate 	return (METAROOT_OK);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate  * Check if stripe, strnp, is a valid root filesystem, ie must
1770Sstevel@tonic-gate  * be single disk stripe, and the the slice, slicenp, if not NULL, must
1780Sstevel@tonic-gate  * be a component of this stripe.
1790Sstevel@tonic-gate  * The arg metaroot is TRUE if strnp is the current root filesystem.
1800Sstevel@tonic-gate  * Returns:
1810Sstevel@tonic-gate  * METAROOT_OK		if stripe is valid and slicenp is a component
1820Sstevel@tonic-gate  * METAROOT_NOTFOUND	if stripe valid but slicenp not a component
1830Sstevel@tonic-gate  * METAROOT_ERR		if stripe not a valid root
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate static int
validate_stripe_root(mdsetname_t * sp,mdname_t * strnp,mdname_t * slicenp,int metaroot,md_error_t * ep)1860Sstevel@tonic-gate validate_stripe_root(
1870Sstevel@tonic-gate 	mdsetname_t	*sp,
1880Sstevel@tonic-gate 	mdname_t	*strnp,
1890Sstevel@tonic-gate 	mdname_t	*slicenp,
1900Sstevel@tonic-gate 	int		metaroot,
1910Sstevel@tonic-gate 	md_error_t	*ep
1920Sstevel@tonic-gate )
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	md_stripe_t	*stripep;
1950Sstevel@tonic-gate 	md_row_t	*rp;
1960Sstevel@tonic-gate 	md_comp_t	*cp;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if ((stripep = meta_get_stripe(sp, strnp, ep)) == NULL) {
1990Sstevel@tonic-gate 		mde_perror(ep, "");
2000Sstevel@tonic-gate 		return (METAROOT_ERR);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 	if (stripep->rows.rows_len != 1) {
2030Sstevel@tonic-gate 		md_eprintf(gettext(
2040Sstevel@tonic-gate 		    "Concat %s has more than 1 slice\n"), strnp->cname);
2050Sstevel@tonic-gate 		return (METAROOT_ERR);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 	rp = &stripep->rows.rows_val[0];
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	if (rp->comps.comps_len != 1) {
2100Sstevel@tonic-gate 		md_eprintf(gettext(
2110Sstevel@tonic-gate 		    "Stripe %s has more than 1 slice\n"), strnp->cname);
2120Sstevel@tonic-gate 		return (METAROOT_ERR);
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 	cp = &rp->comps.comps_val[0];
2150Sstevel@tonic-gate 	if (!metaismeta(cp->compnamep)) {
2160Sstevel@tonic-gate 		if (slicenp == NULL)
2170Sstevel@tonic-gate 			return (METAROOT_OK);
2180Sstevel@tonic-gate 		if (strcmp(slicenp->cname, cp->compnamep->cname) == 0)
2190Sstevel@tonic-gate 			return (METAROOT_OK);
2200Sstevel@tonic-gate 		if (!metaroot) {
2210Sstevel@tonic-gate 			md_eprintf(gettext(
2220Sstevel@tonic-gate 			    "Root %s is not a component of metadevice %s\n"),
2230Sstevel@tonic-gate 			    slicenp->cname, strnp->cname);
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 		return (METAROOT_NOTFOUND);
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 	md_eprintf(gettext(
2280Sstevel@tonic-gate 	    "Component %s is not a stripe\n"), cp->compnamep->cname);
2290Sstevel@tonic-gate 	return (METAROOT_ERR);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Check if the device devnp is valid. It must be a component of the
2340Sstevel@tonic-gate  * metadevice that contains the root filesystem
2350Sstevel@tonic-gate  */
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate static int
validate_root_device(mdsetname_t * sp,mdname_t * devnp,md_error_t * ep)2380Sstevel@tonic-gate validate_root_device(
2390Sstevel@tonic-gate 	mdsetname_t	*sp,
2400Sstevel@tonic-gate 	mdname_t	*devnp,
2410Sstevel@tonic-gate 	md_error_t	*ep
2420Sstevel@tonic-gate )
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	mdname_t	*rootnp;
2450Sstevel@tonic-gate 	char		*curroot;
2460Sstevel@tonic-gate 	char		*miscname;
2470Sstevel@tonic-gate 	int		rval;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if ((curroot = meta_get_current_root(ep)) == NULL) {
2500Sstevel@tonic-gate 		mde_perror(ep, "");
2510Sstevel@tonic-gate 		return (METAROOT_ERR);
2520Sstevel@tonic-gate 	}
253*1623Stw21770 	if ((rootnp = metaname(&sp, curroot, UNKNOWN, ep)) == NULL) {
2540Sstevel@tonic-gate 		mde_perror(ep, "");
2550Sstevel@tonic-gate 		return (METAROOT_ERR);
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if (metaismeta(rootnp)) {
2590Sstevel@tonic-gate 		/* get type */
2600Sstevel@tonic-gate 		if ((miscname = metagetmiscname(rootnp, ep)) == NULL) {
2610Sstevel@tonic-gate 			mde_perror(ep, "");
2620Sstevel@tonic-gate 			return (METAROOT_ERR);
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 		if (strcmp(miscname, MD_MIRROR) == 0) {
2650Sstevel@tonic-gate 			if ((rval = validate_mirror_root(sp, rootnp,
2660Sstevel@tonic-gate 			    devnp, 1, ep)) == METAROOT_OK)
2670Sstevel@tonic-gate 				return (METAROOT_OK);
2680Sstevel@tonic-gate 			if (rval == METAROOT_NOTFOUND) {
2690Sstevel@tonic-gate 				md_eprintf(gettext(
2700Sstevel@tonic-gate 				    "Slice %s is not a component of root %s\n"),
2710Sstevel@tonic-gate 				    devnp->cname, rootnp->cname);
2720Sstevel@tonic-gate 			}
2730Sstevel@tonic-gate 			return (METAROOT_ERR);
2740Sstevel@tonic-gate 		} else if (strcmp(miscname, MD_STRIPE) == 0) {
2750Sstevel@tonic-gate 			if ((rval = validate_stripe_root(sp, rootnp,
2760Sstevel@tonic-gate 			    devnp, 1, ep)) == METAROOT_OK)
2770Sstevel@tonic-gate 				return (METAROOT_OK);
2780Sstevel@tonic-gate 			if (rval == METAROOT_NOTFOUND) {
2790Sstevel@tonic-gate 				md_eprintf(gettext(
2800Sstevel@tonic-gate 				    "Slice %s is not a component of root %s\n"),
2810Sstevel@tonic-gate 				    devnp->cname, rootnp->cname);
2820Sstevel@tonic-gate 			}
2830Sstevel@tonic-gate 			return (METAROOT_ERR);
2840Sstevel@tonic-gate 		} else {
2850Sstevel@tonic-gate 			md_eprintf(gettext(
2860Sstevel@tonic-gate 			    "Root metadevice, %s, is not a Slice or Mirror\n"),
2870Sstevel@tonic-gate 			    rootnp->cname);
2880Sstevel@tonic-gate 			return (METAROOT_ERR);
2890Sstevel@tonic-gate 		}
2900Sstevel@tonic-gate 	} else {
2910Sstevel@tonic-gate 		md_eprintf(gettext(
2920Sstevel@tonic-gate 		    "Current Root %s is not a metadevice\n"), rootnp->cname);
2930Sstevel@tonic-gate 		return (METAROOT_ERR);
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate /*
2980Sstevel@tonic-gate  * What we're going to do:
2990Sstevel@tonic-gate  *
3000Sstevel@tonic-gate  * 1) Check if the device is a metadevice or not.
3010Sstevel@tonic-gate  *
3020Sstevel@tonic-gate  * 2) If a metadevice, and it is valid, ie a stripe or a mirror containing
3030Sstevel@tonic-gate  *    a single slice, add "forceload:{drv,misc}/<modname>" of
3040Sstevel@tonic-gate  *    underlying drivers for the meta-root and the metadevice
3050Sstevel@tonic-gate  *    database to system. Otherwise, remove forceloads from system if the
3060Sstevel@tonic-gate  *    slice is a component of the current root metadevice.
3070Sstevel@tonic-gate  *
3080Sstevel@tonic-gate  * 3) Add "rootdev:/devices/..." to system.
3090Sstevel@tonic-gate  *
3100Sstevel@tonic-gate  * 4) Replace / mount in vfstab.
3110Sstevel@tonic-gate  *
3120Sstevel@tonic-gate  * 5) Repatch database locations, just to be safe.
3130Sstevel@tonic-gate  */
3140Sstevel@tonic-gate int
main(int argc,char * argv[])3150Sstevel@tonic-gate main(
3160Sstevel@tonic-gate 	int		argc,
3170Sstevel@tonic-gate 	char		*argv[]
3180Sstevel@tonic-gate )
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	int		i;
3210Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
3220Sstevel@tonic-gate 	mdname_t	*rootnp;
3230Sstevel@tonic-gate 	int		c;
3240Sstevel@tonic-gate 	int		ckmv_flag = 0;	/* non-zero if -c, -k, -m or -v */
3250Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
3260Sstevel@tonic-gate 	md_error_t	*ep = &status;
3270Sstevel@tonic-gate 	char		*miscname;
3280Sstevel@tonic-gate 	char		*curroot;
3290Sstevel@tonic-gate 	mdname_t	*currootnp;
3300Sstevel@tonic-gate 	mdname_t	*currootdevnp;
3310Sstevel@tonic-gate 	char		*root_path = NULL;
3320Sstevel@tonic-gate 	struct def_map	*map;
3330Sstevel@tonic-gate 	size_t		root_path_size;
3340Sstevel@tonic-gate 	size_t		path_buf_size;
3350Sstevel@tonic-gate 	int		error;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/*
3380Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
3390Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
3400Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
3410Sstevel@tonic-gate 	 * something.
3420Sstevel@tonic-gate 	 */
3430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
3440Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
3450Sstevel@tonic-gate #endif
3460Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3470Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	if ((sdssc_bind_library() == SDSSC_OKAY) &&
3500Sstevel@tonic-gate 		(sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
3510Sstevel@tonic-gate 		    &error) == SDSSC_PROXY_DONE))
3520Sstevel@tonic-gate 			exit(error);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/* initialize */
3550Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0 ||
3560Sstevel@tonic-gate 			meta_check_root(ep) != 0) {
3570Sstevel@tonic-gate 		mde_perror(ep, "");
3580Sstevel@tonic-gate 		md_exit(sp, 1);
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	/* parse options */
3620Sstevel@tonic-gate 	optind = 1;
3630Sstevel@tonic-gate 	opterr = 1;
3640Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "hnk:m:v:c:R:?")) != -1) {
3650Sstevel@tonic-gate 		switch (c) {
3660Sstevel@tonic-gate 		case 'h':
3670Sstevel@tonic-gate 			usage(sp, 0);
3680Sstevel@tonic-gate 			break;
3690Sstevel@tonic-gate 		case 'm':
3700Sstevel@tonic-gate 			dbname = optarg;
3710Sstevel@tonic-gate 			ckmv_flag = 1;
3720Sstevel@tonic-gate 			break;
3730Sstevel@tonic-gate 		case 'n':
3740Sstevel@tonic-gate 			doit = 0;
3750Sstevel@tonic-gate 			verbose = 1;
3760Sstevel@tonic-gate 			break;
3770Sstevel@tonic-gate 		case 'k':
3780Sstevel@tonic-gate 			sname = optarg;
3790Sstevel@tonic-gate 			ckmv_flag = 1;
3800Sstevel@tonic-gate 			break;
3810Sstevel@tonic-gate 		case 'v':
3820Sstevel@tonic-gate 			vname = optarg;
3830Sstevel@tonic-gate 			ckmv_flag = 1;
3840Sstevel@tonic-gate 			break;
3850Sstevel@tonic-gate 		case 'c':
3860Sstevel@tonic-gate 			cname = optarg;
3870Sstevel@tonic-gate 			ckmv_flag = 1;
3880Sstevel@tonic-gate 			break;
3890Sstevel@tonic-gate 		case 'R':
3900Sstevel@tonic-gate 			root_path = optarg;
3910Sstevel@tonic-gate 			break;
3920Sstevel@tonic-gate 		case '?':
3930Sstevel@tonic-gate 			if (optopt == '?')
3940Sstevel@tonic-gate 				usage(sp, 0);
3950Sstevel@tonic-gate 			/*FALLTHROUGH*/
3960Sstevel@tonic-gate 		default:
3970Sstevel@tonic-gate 			usage(sp, 1);
3980Sstevel@tonic-gate 			break;
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 	argc -= optind;
4020Sstevel@tonic-gate 	argv += optind;
4030Sstevel@tonic-gate 	if (argc != 1)
4040Sstevel@tonic-gate 		usage(sp, 1);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/* Can't use -R with any of -c, -k, -m or -v */
4070Sstevel@tonic-gate 	if ((ckmv_flag != 0) && (root_path != NULL)) {
4080Sstevel@tonic-gate 		md_eprintf(
4090Sstevel@tonic-gate 			gettext("-R invalid with any of -c, -k, -m or -v\n"));
4100Sstevel@tonic-gate 		usage(sp, 1);
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/* get device name */
414*1623Stw21770 	if ((rootnp = metaname(&sp, argv[0], UNKNOWN, ep)) == NULL) {
4150Sstevel@tonic-gate 		mde_perror(ep, "");
4160Sstevel@tonic-gate 		md_exit(sp, 1);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 	if ((curroot = meta_get_current_root(ep)) == NULL) {
4190Sstevel@tonic-gate 		mde_perror(ep, "");
4200Sstevel@tonic-gate 		md_exit(sp, 1);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 	/*
4230Sstevel@tonic-gate 	 * Get device name of current root metadevice.  If root is net
4240Sstevel@tonic-gate 	 * mounted as happens if this command is part of the install
4250Sstevel@tonic-gate 	 * process, currootnp will be set to NULL.
4260Sstevel@tonic-gate 	 */
427*1623Stw21770 	currootnp = metaname(&sp, curroot, UNKNOWN, ep);
4280Sstevel@tonic-gate 	/*
4290Sstevel@tonic-gate 	 * If the argument is the name of the current root filesystem, then
4300Sstevel@tonic-gate 	 * the command is allowed, otherwise check that the argument is
4310Sstevel@tonic-gate 	 * valid.
4320Sstevel@tonic-gate 	 */
4330Sstevel@tonic-gate 	if ((currootnp == NULL) ||
4340Sstevel@tonic-gate 		(strcmp(currootnp->cname, rootnp->cname) != 0)) {
4350Sstevel@tonic-gate 		if (metaismeta(rootnp)) {
4360Sstevel@tonic-gate 			/*
4370Sstevel@tonic-gate 			 * Validate that the metadevice is based on a
4380Sstevel@tonic-gate 			 * single slice. If none of the -k, -m, -v, -c or
4390Sstevel@tonic-gate 			 * -R options are specified, then the default
4400Sstevel@tonic-gate 			 * system files are being modified and hence the
4410Sstevel@tonic-gate 			 * current root slice must be a component of the
4420Sstevel@tonic-gate 			 * metadevice. If any of the previously mentioned
4430Sstevel@tonic-gate 			 * options are used don't check that the current
4440Sstevel@tonic-gate 			 * root is a component.
4450Sstevel@tonic-gate 			 */
4460Sstevel@tonic-gate 			if ((ckmv_flag == 0) && (root_path == NULL)) {
4470Sstevel@tonic-gate 				/* Get device name of current root slice */
4480Sstevel@tonic-gate 				if ((currootdevnp =
4490Sstevel@tonic-gate 				    meta_get_current_root_dev(sp, ep))
4500Sstevel@tonic-gate 				    == NULL) {
4510Sstevel@tonic-gate 					mde_perror(ep, "");
4520Sstevel@tonic-gate 					md_exit(sp, 1);
4530Sstevel@tonic-gate 				}
4540Sstevel@tonic-gate 			} else currootdevnp = NULL;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 			if ((miscname = metagetmiscname(rootnp, ep)) == NULL) {
4570Sstevel@tonic-gate 				mde_perror(ep, "");
4580Sstevel@tonic-gate 				md_exit(sp, 1);
4590Sstevel@tonic-gate 			}
4600Sstevel@tonic-gate 			/* Check that metadevice is a mirror or a stripe */
4610Sstevel@tonic-gate 			if (strcmp(miscname, MD_MIRROR) == 0) {
4620Sstevel@tonic-gate 				if (validate_mirror_root(sp, rootnp,
4630Sstevel@tonic-gate 				    currootdevnp, 0, ep) != METAROOT_OK) {
4640Sstevel@tonic-gate 					md_exit(sp, 1);
4650Sstevel@tonic-gate 				}
4660Sstevel@tonic-gate 			} else if (strcmp(miscname, MD_STRIPE) == 0) {
4670Sstevel@tonic-gate 				if (validate_stripe_root(sp, rootnp,
4680Sstevel@tonic-gate 				    currootdevnp, 0, ep) != METAROOT_OK) {
4690Sstevel@tonic-gate 					md_exit(sp, 1);
4700Sstevel@tonic-gate 				}
4710Sstevel@tonic-gate 			} else {
4720Sstevel@tonic-gate 				md_eprintf(gettext(
4730Sstevel@tonic-gate 				    "%s is not a mirror or stripe\n"),
4740Sstevel@tonic-gate 				    rootnp->cname);
4750Sstevel@tonic-gate 				md_exit(sp, 1);
4760Sstevel@tonic-gate 			}
4770Sstevel@tonic-gate 		} else {
4780Sstevel@tonic-gate 			/*
4790Sstevel@tonic-gate 			 * Check that the root device is a component of the
4800Sstevel@tonic-gate 			 * current root filesystem only if the default system
4810Sstevel@tonic-gate 			 * files are being modified
4820Sstevel@tonic-gate 			 */
4830Sstevel@tonic-gate 			if ((ckmv_flag == 0) && (root_path == NULL)) {
4840Sstevel@tonic-gate 				if (validate_root_device(sp, rootnp, ep) != 0) {
4850Sstevel@tonic-gate 					md_exit(sp, 1);
4860Sstevel@tonic-gate 				}
4870Sstevel@tonic-gate 			}
4880Sstevel@tonic-gate 		}
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	if (meta_lock(sp, TRUE, ep)) {
4920Sstevel@tonic-gate 		mde_perror(ep, "");
4930Sstevel@tonic-gate 		md_exit(sp, 1);
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	/*
4970Sstevel@tonic-gate 	 * If -R is specified, use the default system file names relative
4980Sstevel@tonic-gate 	 * to the new root location.
4990Sstevel@tonic-gate 	 */
5000Sstevel@tonic-gate 	if (root_path != NULL) {
5010Sstevel@tonic-gate 		root_path_size = strlen(root_path);
5020Sstevel@tonic-gate 		for (i = 0, map = default_names;
5030Sstevel@tonic-gate 			i < sizeof (default_names) / sizeof (struct def_map);
5040Sstevel@tonic-gate 			i++, map++) {
5050Sstevel@tonic-gate 			/* Add 1 for null terminator */
5060Sstevel@tonic-gate 			path_buf_size = root_path_size +
5070Sstevel@tonic-gate 				strlen(map->dm_default) + 1;
5080Sstevel@tonic-gate 			*map->dm_fname = malloc(path_buf_size);
5090Sstevel@tonic-gate 			if (*map->dm_fname == NULL) {
5100Sstevel@tonic-gate 				md_eprintf(gettext("Cannot allocate memory \
5110Sstevel@tonic-gate for system file path relocation\n"));
5120Sstevel@tonic-gate 				md_exit(sp, 1);
5130Sstevel@tonic-gate 			}
5140Sstevel@tonic-gate 			(void) snprintf(*map->dm_fname, path_buf_size,
5150Sstevel@tonic-gate 					"%s%s", root_path, map->dm_default);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	/* patch system and vfstab for root and mddb locations */
5200Sstevel@tonic-gate 	if (meta_patch_rootdev(rootnp, sname, vname, cname, dbname, doit,
5210Sstevel@tonic-gate 	    verbose, ep) != 0) {
5220Sstevel@tonic-gate 		if (root_path != NULL) {
5230Sstevel@tonic-gate 			free_mem();
5240Sstevel@tonic-gate 		}
5250Sstevel@tonic-gate 		mde_perror(ep, "");
5260Sstevel@tonic-gate 		md_exit(sp, 1);
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 	if (root_path != NULL) {
5290Sstevel@tonic-gate 		free_mem();
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	/* return success */
5330Sstevel@tonic-gate 	md_exit(sp, 0);
5340Sstevel@tonic-gate 	/*NOTREACHED*/
5350Sstevel@tonic-gate 	return (0);
5360Sstevel@tonic-gate }
537