xref: /onnv-gate/usr/src/cmd/lvm/util/metadb.c (revision 2150:e99313126b1a)
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
51623Stw21770  * Common Development and Distribution License (the "License").
61623Stw21770  * 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 /*
221623Stw21770  * 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  * Metadevice database utility.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <meta.h>
330Sstevel@tonic-gate #define	MDDB
340Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
350Sstevel@tonic-gate #include <sdssc.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate enum mddb_cmd {none, attach, detach, patch, infolong, infoshort};
380Sstevel@tonic-gate 
390Sstevel@tonic-gate extern int	procsigs(int block, sigset_t *oldsigs, md_error_t *ep);
400Sstevel@tonic-gate 
410Sstevel@tonic-gate static void
usage(mdsetname_t * sp,char * string)420Sstevel@tonic-gate usage(
430Sstevel@tonic-gate 	mdsetname_t	*sp,
440Sstevel@tonic-gate 	char		*string
450Sstevel@tonic-gate )
460Sstevel@tonic-gate {
470Sstevel@tonic-gate 	if ((string != NULL) && (*string != '\0'))
480Sstevel@tonic-gate 		md_eprintf("%s\n", string);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
510Sstevel@tonic-gate "usage:  %s [-s setname] -a [options] mddbnnn\n"
520Sstevel@tonic-gate "	%s [-s setname] -a [options] device ...\n"
530Sstevel@tonic-gate "	%s [-s setname] -d [options] mddbnnn\n"
540Sstevel@tonic-gate "	%s [-s setname] -d [options] device ...\n"
550Sstevel@tonic-gate "	%s [-s setname] -i \n"
560Sstevel@tonic-gate "	%s -p [options] [ mddb.cf-file ]\n"
570Sstevel@tonic-gate "options:\n"
580Sstevel@tonic-gate "-c count	number of replicas (for use with -a only)\n"
590Sstevel@tonic-gate "-f		force adding or deleting of replicas\n"
600Sstevel@tonic-gate "-k filename	alternate /etc/system file\n"
610Sstevel@tonic-gate "-l length	specify size of replica (for use with -a only)\n"),
620Sstevel@tonic-gate 	    myname, myname, myname, myname, myname, myname);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	md_exit(sp, (string == NULL) ? 0 : 1);
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static mdname_t *
make_dbname(mdsetname_t * sp,mdnamelist_t ** nlp,char * name,md_error_t * ep)680Sstevel@tonic-gate make_dbname(
690Sstevel@tonic-gate 	mdsetname_t	*sp,
700Sstevel@tonic-gate 	mdnamelist_t	**nlp,
710Sstevel@tonic-gate 	char		*name,
720Sstevel@tonic-gate 	md_error_t	*ep
730Sstevel@tonic-gate )
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	mdname_t	*np;
760Sstevel@tonic-gate 
771623Stw21770 	if ((np = metaname(&sp, name, LOGICAL_DEVICE, ep)) == NULL)
780Sstevel@tonic-gate 		return (NULL);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	return (metanamelist_append(nlp, np));
810Sstevel@tonic-gate }
820Sstevel@tonic-gate 
830Sstevel@tonic-gate static mdnamelist_t *
get_dbnames_fromfile(mdsetname_t * sp,mdnamelist_t ** nlp,char * tabname,int * dbsize,int * dbcnt,int * default_size,md_error_t * ep)840Sstevel@tonic-gate get_dbnames_fromfile(
850Sstevel@tonic-gate 	mdsetname_t	*sp,
860Sstevel@tonic-gate 	mdnamelist_t	**nlp,
870Sstevel@tonic-gate 	char		*tabname,
880Sstevel@tonic-gate 	int		*dbsize,
890Sstevel@tonic-gate 	int		*dbcnt,
900Sstevel@tonic-gate 	int		*default_size,
910Sstevel@tonic-gate 	md_error_t	*ep
920Sstevel@tonic-gate )
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	md_tab_t	*tabp = NULL;
950Sstevel@tonic-gate 	md_tab_line_t	*linep = NULL;
960Sstevel@tonic-gate 	int		argc;
970Sstevel@tonic-gate 	char		**argv;
980Sstevel@tonic-gate 	char		*context;
990Sstevel@tonic-gate 	int		save = optind;
1000Sstevel@tonic-gate 	int		c;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/* look in md.tab */
1030Sstevel@tonic-gate 	if ((tabp = meta_tab_parse(NULL, ep)) == NULL) {
1040Sstevel@tonic-gate 		if (! mdissyserror(ep, ENOENT))
1050Sstevel@tonic-gate 			mde_perror(ep, "");
1060Sstevel@tonic-gate 		mdclrerror(ep);
1070Sstevel@tonic-gate 		return (NULL);
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	if ((linep = meta_tab_find(sp, tabp, tabname, TAB_MDDB)) == NULL) {
1110Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOENT, tabname);
1120Sstevel@tonic-gate 		goto out;
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 	argc = linep->argc;
1150Sstevel@tonic-gate 	argv = linep->argv;
1160Sstevel@tonic-gate 	context = linep->context;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	/* parse up entry */
1190Sstevel@tonic-gate 	optind = 1;
1200Sstevel@tonic-gate 	opterr = 1;
1210Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "c:l:")) != -1) {
1220Sstevel@tonic-gate 		switch (c) {
1230Sstevel@tonic-gate 		case 'c':
1240Sstevel@tonic-gate 			if (sscanf(optarg, "%d", dbcnt) != 1) {
1250Sstevel@tonic-gate 				md_eprintf("%s: %s\n",
1260Sstevel@tonic-gate 				    context, gettext("bad format"));
1270Sstevel@tonic-gate 				usage(sp, "");
1280Sstevel@tonic-gate 			}
1290Sstevel@tonic-gate 			break;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 		case 'l':
1320Sstevel@tonic-gate 			if (sscanf(optarg, "%d", dbsize) != 1) {
1330Sstevel@tonic-gate 				md_eprintf("%s: %s\n",
1340Sstevel@tonic-gate 				    context, gettext("bad format"));
1350Sstevel@tonic-gate 				usage(sp, "");
1360Sstevel@tonic-gate 			}
1370Sstevel@tonic-gate 			*default_size = FALSE;
1380Sstevel@tonic-gate 			break;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		default:
1410Sstevel@tonic-gate 			usage(sp, "");
1420Sstevel@tonic-gate 		}
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 	argc -= optind;
1450Sstevel@tonic-gate 	argv += optind;
1460Sstevel@tonic-gate 	for (; (argc > 0); --argc, ++argv) {
1470Sstevel@tonic-gate 		char	*token = argv[0];
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 		if (make_dbname(sp, nlp, token, ep) == NULL) {
1500Sstevel@tonic-gate 			metafreenamelist(*nlp);
1510Sstevel@tonic-gate 			*nlp = NULL;
1520Sstevel@tonic-gate 			goto out;
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	/* cleanup, return list */
1570Sstevel@tonic-gate out:
1580Sstevel@tonic-gate 	if (tabp != NULL)
1590Sstevel@tonic-gate 		meta_tab_free(tabp);
1600Sstevel@tonic-gate 	optind = save;
1610Sstevel@tonic-gate 	return (*nlp);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate  * built list of all devices which are to be detached
1660Sstevel@tonic-gate  */
1670Sstevel@tonic-gate static mdnamelist_t *
build_a_namelist(mdsetname_t * sp,int argc,char ** argv,md_error_t * ep)1680Sstevel@tonic-gate build_a_namelist(
1690Sstevel@tonic-gate 	mdsetname_t	*sp,
1700Sstevel@tonic-gate 	int		argc,
1710Sstevel@tonic-gate 	char		**argv,
1720Sstevel@tonic-gate 	md_error_t	*ep
1730Sstevel@tonic-gate )
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	int		i;
1760Sstevel@tonic-gate 	int		dbsize, dbcnt, default_size;
1770Sstevel@tonic-gate 	mdnamelist_t	*dbnlp = NULL;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
1800Sstevel@tonic-gate 		if (strncmp(argv[i], "mddb", 4) == 0) {
1810Sstevel@tonic-gate 			if (get_dbnames_fromfile(sp, &dbnlp, argv[i],
1820Sstevel@tonic-gate 			    &dbsize, &dbcnt, &default_size, ep) == NULL) {
1830Sstevel@tonic-gate 				/* don't freelist here - already been done */
1840Sstevel@tonic-gate 				return (NULL);
1850Sstevel@tonic-gate 			}
1860Sstevel@tonic-gate 			continue;
1870Sstevel@tonic-gate 		}
1880Sstevel@tonic-gate 		if (make_dbname(sp, &dbnlp, argv[i], ep) == NULL) {
1890Sstevel@tonic-gate 			metafreenamelist(dbnlp);
1900Sstevel@tonic-gate 			return (NULL);
1910Sstevel@tonic-gate 		}
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	return (dbnlp);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate  * built the next list of devices which are to be attached
2000Sstevel@tonic-gate  * that have the same size and count of replicas.
2010Sstevel@tonic-gate  */
2020Sstevel@tonic-gate static mdnamelist_t *
build_next_namelist(mdsetname_t * sp,int argc,char ** argv,int * arg_index,int * dbsize,int * dbcnt,int * default_size,md_error_t * ep)2030Sstevel@tonic-gate build_next_namelist(
2040Sstevel@tonic-gate 	mdsetname_t	*sp,
2050Sstevel@tonic-gate 	int		argc,
2060Sstevel@tonic-gate 	char		**argv,
2070Sstevel@tonic-gate 	int		*arg_index,
2080Sstevel@tonic-gate 	int		*dbsize,
2090Sstevel@tonic-gate 	int		*dbcnt,
2100Sstevel@tonic-gate 	int		*default_size,
2110Sstevel@tonic-gate 	md_error_t	*ep
2120Sstevel@tonic-gate )
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	int		i;
2150Sstevel@tonic-gate 	mdnamelist_t	*dbnlp = NULL;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	for (i = *arg_index; i < argc; i++) {
2180Sstevel@tonic-gate 		if (strncmp(argv[i], "mddb", 4) == 0) {
2190Sstevel@tonic-gate 			/*
2200Sstevel@tonic-gate 			 * If we have stuff in the namelist
2210Sstevel@tonic-gate 			 * return it before processing the mddb entry.
2220Sstevel@tonic-gate 			 */
2230Sstevel@tonic-gate 			if (dbnlp) {
2240Sstevel@tonic-gate 				*arg_index = i;
2250Sstevel@tonic-gate 				return (dbnlp);
2260Sstevel@tonic-gate 			}
2270Sstevel@tonic-gate 			if (get_dbnames_fromfile(sp, &dbnlp, argv[i],
2280Sstevel@tonic-gate 			    dbsize, dbcnt, default_size, ep) == NULL) {
2290Sstevel@tonic-gate 				/* don't freelist here - already been done */
2300Sstevel@tonic-gate 				return (NULL);
2310Sstevel@tonic-gate 			}
2320Sstevel@tonic-gate 			*arg_index = i + 1;
2330Sstevel@tonic-gate 			return (dbnlp);
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 		if (make_dbname(sp, &dbnlp, argv[i], ep) == NULL) {
2360Sstevel@tonic-gate 			metafreenamelist(dbnlp);
2370Sstevel@tonic-gate 			return (NULL);
2380Sstevel@tonic-gate 		}
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 	*arg_index = argc;
2410Sstevel@tonic-gate 	return (dbnlp);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static int
chngdb(mdsetname_t * sp,enum mddb_cmd cmd,int argc,char * argv[],uint_t options,md_error_t * ep)2460Sstevel@tonic-gate chngdb(
2470Sstevel@tonic-gate 	mdsetname_t	*sp,
2480Sstevel@tonic-gate 	enum mddb_cmd	cmd,
2490Sstevel@tonic-gate 	int		argc,
2500Sstevel@tonic-gate 	char		*argv[],
2510Sstevel@tonic-gate 	uint_t		options,
2520Sstevel@tonic-gate 	md_error_t	*ep
2530Sstevel@tonic-gate )
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	int		c;
2560Sstevel@tonic-gate 	int		i;
2570Sstevel@tonic-gate 	md_error_t	xep = mdnullerror;
2580Sstevel@tonic-gate 	mdnamelist_t	*dbnlp = NULL;
2590Sstevel@tonic-gate 	int		dbsize = MD_DBSIZE;
2600Sstevel@tonic-gate 	int		maxblks = MDDB_MAXBLKS;
2610Sstevel@tonic-gate 	int		minblks = MDDB_MINBLKS;
2620Sstevel@tonic-gate 	int		dbcnt = 1;
2630Sstevel@tonic-gate 	mdforceopts_t	force = MDFORCE_NONE;
2640Sstevel@tonic-gate 	int		rval = 0;
2650Sstevel@tonic-gate 	char		*sysfilename = NULL;
2660Sstevel@tonic-gate 	int		default_size = TRUE;
2670Sstevel@tonic-gate 	md_set_desc	*sd;
2680Sstevel@tonic-gate 	md_setkey_t	*cl_sk;
2690Sstevel@tonic-gate 	md_mnnode_desc	*nd;
2700Sstevel@tonic-gate 	int		suspend1_flag = 0;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/* reset and parse args */
2730Sstevel@tonic-gate 	optind = 1;
2740Sstevel@tonic-gate 	opterr = 1;
2750Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ac:dfk:pl:s:")) != -1) {
2760Sstevel@tonic-gate 		switch (c) {
2770Sstevel@tonic-gate 		case 'a':
2780Sstevel@tonic-gate 			break;
2790Sstevel@tonic-gate 		case 'c':
2800Sstevel@tonic-gate 			if (sscanf(optarg, "%d", &dbcnt) != 1) {
2810Sstevel@tonic-gate 				md_eprintf("%s: %s\n",
2820Sstevel@tonic-gate 				    optarg, gettext("bad format"));
2830Sstevel@tonic-gate 				usage(sp, "");
2840Sstevel@tonic-gate 			}
2850Sstevel@tonic-gate 			break;
2860Sstevel@tonic-gate 		case 'd':
2870Sstevel@tonic-gate 			break;
2880Sstevel@tonic-gate 		case 'f':
2890Sstevel@tonic-gate 			force = MDFORCE_LOCAL;
2900Sstevel@tonic-gate 			break;
2910Sstevel@tonic-gate 		case 'k':
2920Sstevel@tonic-gate 			sysfilename = optarg;
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 		case 'l':
2950Sstevel@tonic-gate 			if (sscanf(optarg, "%d", &dbsize) != 1) {
2960Sstevel@tonic-gate 				md_eprintf("%s: %s\n",
2970Sstevel@tonic-gate 				    optarg, gettext("bad format"));
2980Sstevel@tonic-gate 				usage(sp, "");
2990Sstevel@tonic-gate 			}
3000Sstevel@tonic-gate 			default_size = FALSE;
3010Sstevel@tonic-gate 			break;
3020Sstevel@tonic-gate 		case 'p':
3030Sstevel@tonic-gate 			break;
3040Sstevel@tonic-gate 		case 's':
3050Sstevel@tonic-gate 			break;
3060Sstevel@tonic-gate 		default:
3070Sstevel@tonic-gate 			usage(sp, "");
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	/*
3120Sstevel@tonic-gate 	 * If it is a multinode diskset, use appropriate metadb size.
3130Sstevel@tonic-gate 	 */
3140Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
3150Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
3160Sstevel@tonic-gate 			return (-1);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
3190Sstevel@tonic-gate 			maxblks = MDDB_MN_MAXBLKS;
3200Sstevel@tonic-gate 			minblks = MDDB_MN_MINBLKS;
3210Sstevel@tonic-gate 			if (default_size)
3220Sstevel@tonic-gate 				dbsize = MD_MN_DBSIZE;
3230Sstevel@tonic-gate 		}
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	if (dbsize > maxblks)
3270Sstevel@tonic-gate 		usage(sp, gettext("size (-l) is too big"));
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (dbsize < minblks)
3310Sstevel@tonic-gate 		usage(sp, gettext("size (-l) is too small"));
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (dbcnt < 1)
3340Sstevel@tonic-gate 		usage(sp, gettext(
3350Sstevel@tonic-gate 		    "count (-c) must be 1 or more"));
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	argc -= optind;
3390Sstevel@tonic-gate 	argv += optind;
3400Sstevel@tonic-gate 	if (argc <= 0) {
3410Sstevel@tonic-gate 		usage(sp, gettext(
3420Sstevel@tonic-gate 		    "no devices specified to attach or detach"));
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
3480Sstevel@tonic-gate 			md_error_t xep = mdnullerror;
3490Sstevel@tonic-gate 			sigset_t sigs;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 			/* Make sure we are blocking all signals */
3520Sstevel@tonic-gate 			if (procsigs(TRUE, &sigs, &xep) < 0)
3530Sstevel@tonic-gate 				mdclrerror(&xep);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 			/*
3560Sstevel@tonic-gate 			 * Lock out other metaset or metadb commands
3570Sstevel@tonic-gate 			 * across the diskset.
3580Sstevel@tonic-gate 			 */
3590Sstevel@tonic-gate 			nd = sd->sd_nodelist;
3600Sstevel@tonic-gate 			while (nd) {
3610Sstevel@tonic-gate 				if ((force & MDFORCE_LOCAL) &&
3620Sstevel@tonic-gate 				    strcmp(nd->nd_nodename, mynode()) != 0) {
3630Sstevel@tonic-gate 					nd = nd->nd_next;
3640Sstevel@tonic-gate 					continue;
3650Sstevel@tonic-gate 				}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 				if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
3680Sstevel@tonic-gate 					nd = nd->nd_next;
3690Sstevel@tonic-gate 					continue;
3700Sstevel@tonic-gate 				}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 				if (clnt_lock_set(nd->nd_nodename, sp, ep)) {
3730Sstevel@tonic-gate 					rval = -1;
3740Sstevel@tonic-gate 					goto done;
3750Sstevel@tonic-gate 				}
3760Sstevel@tonic-gate 				nd = nd->nd_next;
3770Sstevel@tonic-gate 			}
3780Sstevel@tonic-gate 			/*
3790Sstevel@tonic-gate 			 * Lock out other meta* commands by suspending
3800Sstevel@tonic-gate 			 * class 1 messages across the diskset.
3810Sstevel@tonic-gate 			 */
3820Sstevel@tonic-gate 			nd = sd->sd_nodelist;
3830Sstevel@tonic-gate 			while (nd) {
3840Sstevel@tonic-gate 				if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
3850Sstevel@tonic-gate 					nd = nd->nd_next;
3860Sstevel@tonic-gate 					continue;
3870Sstevel@tonic-gate 				}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 				if (clnt_mdcommdctl(nd->nd_nodename,
3900Sstevel@tonic-gate 				    COMMDCTL_SUSPEND, sp, MD_MSG_CLASS1,
3910Sstevel@tonic-gate 				    MD_MSCF_NO_FLAGS, ep)) {
3920Sstevel@tonic-gate 					rval = -1;
3930Sstevel@tonic-gate 					goto done;
3940Sstevel@tonic-gate 				}
3950Sstevel@tonic-gate 				suspend1_flag = 1;
3960Sstevel@tonic-gate 				nd = nd->nd_next;
3970Sstevel@tonic-gate 			}
3980Sstevel@tonic-gate 		} else {
3990Sstevel@tonic-gate 			/* Lock the set on current set members */
4000Sstevel@tonic-gate 			for (i = 0; i < MD_MAXSIDES; i++) {
4010Sstevel@tonic-gate 				/* Skip empty slots */
4020Sstevel@tonic-gate 				if (sd->sd_nodes[i][0] == '\0')
4030Sstevel@tonic-gate 					continue;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 				if ((force & MDFORCE_LOCAL) &&
4060Sstevel@tonic-gate 				    strcmp(sd->sd_nodes[i], mynode()) != 0)
4070Sstevel@tonic-gate 					continue;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 				if (clnt_lock_set(sd->sd_nodes[i], sp, ep)) {
4100Sstevel@tonic-gate 					rval = -1;
4110Sstevel@tonic-gate 					goto done;
4120Sstevel@tonic-gate 				}
4130Sstevel@tonic-gate 			}
4140Sstevel@tonic-gate 		}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 		force |= MDFORCE_SET_LOCKED;
4170Sstevel@tonic-gate 		options |= MDCHK_SET_LOCKED;
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	if (cmd == detach) {
4210Sstevel@tonic-gate 		if ((dbnlp = build_a_namelist(sp, argc, argv, ep)) == NULL) {
4220Sstevel@tonic-gate 			rval = -1;
4230Sstevel@tonic-gate 			goto done;
4240Sstevel@tonic-gate 		}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		rval = meta_db_detach(sp, dbnlp, force, sysfilename, ep);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 		metafreenamelist(dbnlp);
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	if (cmd == attach) {
4320Sstevel@tonic-gate 		daddr_t	nblks = 0;
4330Sstevel@tonic-gate 		int	arg_index = 0;
4340Sstevel@tonic-gate 		int	saved_dbsize = dbsize;
4350Sstevel@tonic-gate 		int	saved_dbcnt = dbcnt;
4360Sstevel@tonic-gate 		int	saved_default_size = default_size;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		if (force & MDFORCE_LOCAL)
4390Sstevel@tonic-gate 			options |= MDCHK_SET_FORCE;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		if (default_size)
4420Sstevel@tonic-gate 			if ((nblks = meta_db_minreplica(sp, ep)) < 0)
4430Sstevel@tonic-gate 				mdclrerror(ep);
4440Sstevel@tonic-gate 		/*
4450Sstevel@tonic-gate 		 * Loop through build a new namelist
4460Sstevel@tonic-gate 		 * for each "mddb" entry or the devices list
4470Sstevel@tonic-gate 		 * on the command line.  This allows each "mddb"
4480Sstevel@tonic-gate 		 * entry to have unique dbsize and dbcnt.
4490Sstevel@tonic-gate 		 */
4500Sstevel@tonic-gate 		while (arg_index < argc) {
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 			dbnlp = build_next_namelist(sp, argc, argv,
4530Sstevel@tonic-gate 			    &arg_index, &dbsize, &dbcnt, &default_size, ep);
4540Sstevel@tonic-gate 			if (dbnlp == NULL) {
4550Sstevel@tonic-gate 				rval = -1;
4560Sstevel@tonic-gate 				goto done;
4570Sstevel@tonic-gate 			}
4580Sstevel@tonic-gate 			/*
4590Sstevel@tonic-gate 			 * If using the default size,
4600Sstevel@tonic-gate 			 *   then let's adjust the default to the minimum
4610Sstevel@tonic-gate 			 *   size currently in use.
4620Sstevel@tonic-gate 			 */
4630Sstevel@tonic-gate 			if (default_size && (nblks > 0))
4640Sstevel@tonic-gate 				dbsize = nblks;	/* adjust replica size */
4650Sstevel@tonic-gate 
466*2150Sjeanm 			if (dbsize > maxblks)
467*2150Sjeanm 				usage(sp, gettext("size (-l) is too big"));
468*2150Sjeanm 
4690Sstevel@tonic-gate 			rval = meta_db_attach(sp, dbnlp, options, NULL, dbcnt,
4700Sstevel@tonic-gate 			    dbsize, sysfilename, ep);
4710Sstevel@tonic-gate 			if (rval) {
4720Sstevel@tonic-gate 				metafreenamelist(dbnlp);
4730Sstevel@tonic-gate 				break;
4740Sstevel@tonic-gate 			}
4750Sstevel@tonic-gate 			dbsize = saved_dbsize;
4760Sstevel@tonic-gate 			dbcnt = saved_dbcnt;
4770Sstevel@tonic-gate 			default_size = saved_default_size;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 			metafreenamelist(dbnlp);
4800Sstevel@tonic-gate 		}
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate done:
4840Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
4850Sstevel@tonic-gate 		cl_sk = cl_get_setkey(sp->setno, sp->setname);
4860Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
4870Sstevel@tonic-gate 			/*
4880Sstevel@tonic-gate 			 * Unlock diskset by resuming
4890Sstevel@tonic-gate 			 * class 1 messages across the diskset.
4900Sstevel@tonic-gate 			 */
4910Sstevel@tonic-gate 			if (suspend1_flag) {
4920Sstevel@tonic-gate 				nd = sd->sd_nodelist;
4930Sstevel@tonic-gate 				while (nd) {
4940Sstevel@tonic-gate 					if (!(nd->nd_flags &
4950Sstevel@tonic-gate 					    MD_MN_NODE_ALIVE)) {
4960Sstevel@tonic-gate 						nd = nd->nd_next;
4970Sstevel@tonic-gate 						continue;
4980Sstevel@tonic-gate 					}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 					if (clnt_mdcommdctl(nd->nd_nodename,
5010Sstevel@tonic-gate 					    COMMDCTL_RESUME, sp,
5020Sstevel@tonic-gate 					    MD_MSG_CLASS1,
5030Sstevel@tonic-gate 					    MD_MSCF_NO_FLAGS, &xep)) {
5040Sstevel@tonic-gate 						mde_perror(&xep, "");
5050Sstevel@tonic-gate 						mdclrerror(&xep);
5060Sstevel@tonic-gate 					}
5070Sstevel@tonic-gate 					nd = nd->nd_next;
5080Sstevel@tonic-gate 				}
5090Sstevel@tonic-gate 			}
5100Sstevel@tonic-gate 			nd = sd->sd_nodelist;
5110Sstevel@tonic-gate 			while (nd) {
5120Sstevel@tonic-gate 				if ((force & MDFORCE_LOCAL) &&
5130Sstevel@tonic-gate 				    strcmp(nd->nd_nodename, mynode()) != 0) {
5140Sstevel@tonic-gate 					nd = nd->nd_next;
5150Sstevel@tonic-gate 					continue;
5160Sstevel@tonic-gate 				}
5170Sstevel@tonic-gate 				if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
5180Sstevel@tonic-gate 					nd = nd->nd_next;
5190Sstevel@tonic-gate 					continue;
5200Sstevel@tonic-gate 				}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 				if (clnt_unlock_set(nd->nd_nodename, cl_sk,
5230Sstevel@tonic-gate 				    &xep))
5240Sstevel@tonic-gate 					mdclrerror(&xep);
5250Sstevel@tonic-gate 				nd = nd->nd_next;
5260Sstevel@tonic-gate 			}
5270Sstevel@tonic-gate 		} else {
5280Sstevel@tonic-gate 			for (i = 0; i < MD_MAXSIDES; i++) {
5290Sstevel@tonic-gate 				/* Skip empty slots */
5300Sstevel@tonic-gate 				if (sd->sd_nodes[i][0] == '\0')
5310Sstevel@tonic-gate 					continue;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 				if ((force & MDFORCE_LOCAL) &&
5340Sstevel@tonic-gate 				    strcmp(sd->sd_nodes[i], mynode()) != 0)
5350Sstevel@tonic-gate 					continue;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 				if (clnt_unlock_set(sd->sd_nodes[i], cl_sk,
5380Sstevel@tonic-gate 				    &xep))
5390Sstevel@tonic-gate 					mdclrerror(&xep);
5400Sstevel@tonic-gate 			}
5410Sstevel@tonic-gate 		}
5420Sstevel@tonic-gate 		cl_set_setkey(NULL);
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	return (rval);
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate static int
info(mdsetname_t * sp,enum mddb_cmd cmd,int print_headers,int print_footers,md_error_t * ep)5490Sstevel@tonic-gate info(
5500Sstevel@tonic-gate 	mdsetname_t	*sp,
5510Sstevel@tonic-gate 	enum mddb_cmd	cmd,
5520Sstevel@tonic-gate 	int		print_headers,
5530Sstevel@tonic-gate 	int		print_footers,
5540Sstevel@tonic-gate 	md_error_t	*ep
5550Sstevel@tonic-gate )
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate 	md_replicalist_t	*rlp = NULL;
5580Sstevel@tonic-gate 	md_replicalist_t	*rl;
5590Sstevel@tonic-gate 	md_replica_t		*r;
5600Sstevel@tonic-gate 	int			i;
5610Sstevel@tonic-gate 	char			*unk_str = NULL;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/* get list of replicas, quit if none */
5640Sstevel@tonic-gate 	if (metareplicalist(sp, (MD_BASICNAME_OK | PRINT_FAST), &rlp, ep) < 0)
5650Sstevel@tonic-gate 		return (-1);
5660Sstevel@tonic-gate 	else if (rlp == NULL)
5670Sstevel@tonic-gate 		return (0);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if (print_headers) {
5700Sstevel@tonic-gate 		(void) printf("\t%5.5s\t\t%9.9s\t%11.11s\n", gettext("flags"),
5710Sstevel@tonic-gate 		    gettext("first blk"), gettext("block count"));
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	unk_str = gettext("unknown");
5750Sstevel@tonic-gate 	for (rl = rlp; rl != NULL; rl = rl->rl_next) {
5760Sstevel@tonic-gate 		r = rl->rl_repp;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		for (i = 0; i < MDDB_FLAGS_LEN; i++) {
5790Sstevel@tonic-gate 			if (r->r_flags & (1 << i))
5800Sstevel@tonic-gate 				(void) putchar(MDDB_FLAGS_STRING[i]);
5810Sstevel@tonic-gate 			else
5820Sstevel@tonic-gate 				(void) putchar(' ');
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 		if ((r->r_blkno == -1) && (r->r_nblk == -1)) {
5860Sstevel@tonic-gate 			(void) printf("\t%7.7s\t\t%7.7s\t", unk_str, unk_str);
5870Sstevel@tonic-gate 		} else if (r->r_nblk == -1) {
5880Sstevel@tonic-gate 			(void) printf("\t%ld\t\t%7.7s\t", r->r_blkno, unk_str);
5890Sstevel@tonic-gate 		} else {
5900Sstevel@tonic-gate 			(void) printf("\t%ld\t\t%ld\t", r->r_blkno, r->r_nblk);
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		(void) printf("\t%s\n", r->r_namep->bname);
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	metafreereplicalist(rlp);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	if (cmd == infoshort)
6000Sstevel@tonic-gate 		return (0);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (!print_footers)
6030Sstevel@tonic-gate 		return (0);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	(void) printf(gettext(
6060Sstevel@tonic-gate 	    " r - replica does not have device relocation information\n"
6070Sstevel@tonic-gate 	    " o - replica active prior to last mddb configuration change\n"
6080Sstevel@tonic-gate 	    " u - replica is up to date\n"
6090Sstevel@tonic-gate 	    " l - locator for this replica was read successfully\n"
6100Sstevel@tonic-gate 	    " c - replica's location was in %s\n"
6110Sstevel@tonic-gate 	    " p - replica's location was patched in kernel\n"
6120Sstevel@tonic-gate 	    " m - replica is master, this is replica selected as input\n"
613*2150Sjeanm 	    " t - tagged data is associated with the replica\n"
6140Sstevel@tonic-gate 	    " W - replica has device write errors\n"
6150Sstevel@tonic-gate 	    " a - replica is active, commits are occurring to this replica\n"
6160Sstevel@tonic-gate 	    " M - replica had problem with master blocks\n"
6170Sstevel@tonic-gate 	    " D - replica had problem with data blocks\n"
6180Sstevel@tonic-gate 	    " F - replica had format problems\n"
6190Sstevel@tonic-gate 	    " S - replica is too small to hold current data base\n"
620*2150Sjeanm 	    " R - replica had device read errors\n"
621*2150Sjeanm 	    " B - tagged data associated with the replica is not valid\n"),
6220Sstevel@tonic-gate 	    META_DBCONF);
6230Sstevel@tonic-gate 	return (0);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate int
main(int argc,char ** argv)6270Sstevel@tonic-gate main(int argc, char **argv)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
6300Sstevel@tonic-gate 	int		c;
6310Sstevel@tonic-gate 	enum mddb_cmd	cmd = none;
6320Sstevel@tonic-gate 	char		*sname = MD_LOCAL_NAME;
6330Sstevel@tonic-gate 	char		*cffilename = NULL;
6340Sstevel@tonic-gate 	char		*sysfilename = NULL;
6350Sstevel@tonic-gate 	int		forceflg = FALSE;
6360Sstevel@tonic-gate 	mdchkopts_t	options = 0;
6370Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
6380Sstevel@tonic-gate 	md_error_t	*ep = &status;
6390Sstevel@tonic-gate 	int		error;
6400Sstevel@tonic-gate 	md_set_desc	*sd;
6410Sstevel@tonic-gate 	int		multi_node = 0;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	/*
6440Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
6450Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
6460Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
6470Sstevel@tonic-gate 	 * something.
6480Sstevel@tonic-gate 	 */
6490Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
6500Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
6510Sstevel@tonic-gate #endif
6520Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
6530Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	if (sdssc_bind_library() == SDSSC_OKAY)
6560Sstevel@tonic-gate 		if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
6570Sstevel@tonic-gate 		    &error) == SDSSC_PROXY_DONE)
6580Sstevel@tonic-gate 			exit(error);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	/* parse args */
6610Sstevel@tonic-gate 	optind = 1;
6620Sstevel@tonic-gate 	opterr = 1;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/* initialize */
6650Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
6660Sstevel@tonic-gate 		mde_perror(ep, "");
6670Sstevel@tonic-gate 		md_exit(sp, 1);
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	/* parse args */
6710Sstevel@tonic-gate 	optind = 1;
6720Sstevel@tonic-gate 	opterr = 1;
6730Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ac:dfhik:l:ps:?")) != -1) {
6740Sstevel@tonic-gate 		switch (c) {
6750Sstevel@tonic-gate 		case 'a':
6760Sstevel@tonic-gate 			cmd = attach;
6770Sstevel@tonic-gate 			break;
6780Sstevel@tonic-gate 		case 'c':
6790Sstevel@tonic-gate 			break;
6800Sstevel@tonic-gate 		case 'd':
6810Sstevel@tonic-gate 			cmd = detach;
6820Sstevel@tonic-gate 			break;
6830Sstevel@tonic-gate 		case 'f':
6840Sstevel@tonic-gate 			forceflg = TRUE;
6850Sstevel@tonic-gate 			break;
6860Sstevel@tonic-gate 		case 'h':
6870Sstevel@tonic-gate 			usage(sp, (char *)0);
6880Sstevel@tonic-gate 			break;
6890Sstevel@tonic-gate 		case 'i':
6900Sstevel@tonic-gate 			cmd = infolong;
6910Sstevel@tonic-gate 			break;
6920Sstevel@tonic-gate 		case 'k':
6930Sstevel@tonic-gate 			sysfilename = optarg;
6940Sstevel@tonic-gate 			break;
6950Sstevel@tonic-gate 		case 'l':
6960Sstevel@tonic-gate 			break;
6970Sstevel@tonic-gate 		case 'p':
6980Sstevel@tonic-gate 			cmd = patch;
6990Sstevel@tonic-gate 			break;
7000Sstevel@tonic-gate 		case 's':
7010Sstevel@tonic-gate 			sname = optarg;
7020Sstevel@tonic-gate 			break;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 		case '?':
7050Sstevel@tonic-gate 			if (optopt == '?')
7060Sstevel@tonic-gate 				usage(sp, NULL);
7070Sstevel@tonic-gate 			/*FALLTHROUGH*/
7080Sstevel@tonic-gate 		default:
7090Sstevel@tonic-gate 			usage(sp, gettext("unknown command"));
7100Sstevel@tonic-gate 		}
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 	if (cmd == none)
7130Sstevel@tonic-gate 		cmd = infoshort;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/* get set context */
7160Sstevel@tonic-gate 	if ((sp = metasetname(sname, ep)) == NULL) {
7170Sstevel@tonic-gate 		mde_perror(ep, "");
7180Sstevel@tonic-gate 		md_exit(sp, 1);
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	/* print status */
7220Sstevel@tonic-gate 	if (cmd == infoshort || cmd == infolong) {
7230Sstevel@tonic-gate 		if (optind != argc)
7240Sstevel@tonic-gate 			usage(sp, gettext(
7250Sstevel@tonic-gate 				"too many arguments"));
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		if (info(sp, cmd, 1, 1, ep)) {
7280Sstevel@tonic-gate 			mde_perror(ep, "");
7290Sstevel@tonic-gate 			md_exit(sp, 1);
7300Sstevel@tonic-gate 		}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 		if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
7330Sstevel@tonic-gate 			mde_perror(ep, "");
7340Sstevel@tonic-gate 			md_exit(sp, 1);
7350Sstevel@tonic-gate 		}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		md_exit(sp, 0);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
7410Sstevel@tonic-gate 		mde_perror(ep, "");
7420Sstevel@tonic-gate 		md_exit(sp, 1);
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
7460Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
7470Sstevel@tonic-gate 			mde_perror(ep, "");
7480Sstevel@tonic-gate 			md_exit(sp, 1);
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
7510Sstevel@tonic-gate 			multi_node = 1;
7520Sstevel@tonic-gate 		}
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	/*
7560Sstevel@tonic-gate 	 * Adjust lock for traditional and local diskset.
7570Sstevel@tonic-gate 	 *
7580Sstevel@tonic-gate 	 * A MN diskset does not use the set meta_lock but instead
7590Sstevel@tonic-gate 	 * uses the clnt_lock of rpc.metad and the suspend/resume
7600Sstevel@tonic-gate 	 * feature of the rpc.mdcommd.  Can't use set meta_lock since
7610Sstevel@tonic-gate 	 * class 1 messages are grabbing this lock and if this thread
7620Sstevel@tonic-gate 	 * is holding the set meta_lock then no rpc.mdcommd suspend
7630Sstevel@tonic-gate 	 * can occur.
7640Sstevel@tonic-gate 	 */
7650Sstevel@tonic-gate 	if ((!multi_node) && (meta_lock(sp, TRUE, ep) != 0)) {
7660Sstevel@tonic-gate 		mde_perror(ep, "");
7670Sstevel@tonic-gate 		md_exit(sp, 1);
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/* check for ownership */
7710Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) != 0) {
7720Sstevel@tonic-gate 		mde_perror(ep, "");
7730Sstevel@tonic-gate 		md_exit(sp, 1);
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/* snarf MDDB locations */
7770Sstevel@tonic-gate 	if (cmd != patch) {
7780Sstevel@tonic-gate 		if (meta_setup_db_locations(ep) != 0) {
7790Sstevel@tonic-gate 			if (! mdismddberror(ep, MDE_DB_STALE)) {
7800Sstevel@tonic-gate 				if (forceflg == FALSE) {
7810Sstevel@tonic-gate 					mde_perror(ep, "");
7820Sstevel@tonic-gate 					md_exit(sp, 1);
7830Sstevel@tonic-gate 				}
7840Sstevel@tonic-gate 				options = MDCHK_ALLOW_NODBS;
7850Sstevel@tonic-gate 			}
7860Sstevel@tonic-gate 			mdclrerror(ep);
7870Sstevel@tonic-gate 		}
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	/* patch MDDB locations */
7910Sstevel@tonic-gate 	if (cmd == patch) {
7920Sstevel@tonic-gate 		if (optind < (argc - 1)) {
7930Sstevel@tonic-gate 			usage(sp, gettext(
7940Sstevel@tonic-gate 			    "too many arguments to -p"));
7950Sstevel@tonic-gate 		}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 		if (optind == (argc - 1))
7980Sstevel@tonic-gate 			cffilename = argv[optind];
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 		if (metaislocalset(sp)) {
8010Sstevel@tonic-gate 			if (meta_db_patch(sysfilename, cffilename, 1, ep)) {
8020Sstevel@tonic-gate 				mde_perror(ep, "");
8030Sstevel@tonic-gate 				md_exit(sp, 1);
8040Sstevel@tonic-gate 			}
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/* add/delete replicas */
8090Sstevel@tonic-gate 	if (cmd == attach || cmd == detach) {
8100Sstevel@tonic-gate 		if (chngdb(sp, cmd, argc, argv, options, ep)) {
8110Sstevel@tonic-gate 			mde_perror(ep, "");
8120Sstevel@tonic-gate 			md_exit(sp, 1);
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	md_exit(sp, 0);
8170Sstevel@tonic-gate 	/*NOTREACHED*/
8180Sstevel@tonic-gate 	return (0);
8190Sstevel@tonic-gate }
820