xref: /onnv-gate/usr/src/cmd/lvm/util/metainit.c (revision 7044:33050d853d04)
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 /*
22*7044Smk117520  * Copyright 2008 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  * initialize metadevices
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <meta.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <sdssc.h>
350Sstevel@tonic-gate #include <sys/lvm/md_mirror.h>
360Sstevel@tonic-gate #include <syslog.h>
370Sstevel@tonic-gate #include "meta_set_prv.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * try to initialize devices
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate #define	DO_AGAIN	0
430Sstevel@tonic-gate #define	DONT_DO		1
440Sstevel@tonic-gate #define	IS_DONE		2
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * mn_send_command
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * generate a command of the form "metainit -s setname [-n] [-f] ....."
500Sstevel@tonic-gate  *
510Sstevel@tonic-gate  * If -n option is *not* set, send the metainit command *with -n set* to
520Sstevel@tonic-gate  * all nodes first. Do this with MD_MSGF_STOP_ON_ERROR set.
530Sstevel@tonic-gate  * That means if it fails on one node, it'll return immediately,
540Sstevel@tonic-gate  * reporting the error.
550Sstevel@tonic-gate  * By doing so, we have a dryrun first that has to succeed on every node
560Sstevel@tonic-gate  * before we start the command for real.
570Sstevel@tonic-gate  * This saves us from backing out a metainit command that succeeded on
580Sstevel@tonic-gate  * some nodes but failed on one.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate static int
mn_send_command(mdsetname_t ** spp,int argc,char ** argv,mdcmdopts_t options,int flags,char * context,md_error_t * ep)610Sstevel@tonic-gate mn_send_command(
620Sstevel@tonic-gate 	mdsetname_t	**spp,
630Sstevel@tonic-gate 	int		argc,
640Sstevel@tonic-gate 	char		**argv,
650Sstevel@tonic-gate 	mdcmdopts_t	options,
660Sstevel@tonic-gate 	int		flags,
670Sstevel@tonic-gate 	char		*context,
680Sstevel@tonic-gate 	md_error_t	*ep
690Sstevel@tonic-gate )
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	int		newargc;
720Sstevel@tonic-gate 	char		**newargv;
730Sstevel@tonic-gate 	int		i;
740Sstevel@tonic-gate 	int		ret;
750Sstevel@tonic-gate 	int		dryrun_only = 0;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	newargv = calloc(argc+5, sizeof (char *));
790Sstevel@tonic-gate 	newargv[0] = "metainit";
800Sstevel@tonic-gate 	newargv[1] = "-s";
810Sstevel@tonic-gate 	newargv[2] = (*spp)->setname;
820Sstevel@tonic-gate 	newargv[3] = "-n"; /* always do "-n" first */
830Sstevel@tonic-gate 	newargc = 4;
840Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
850Sstevel@tonic-gate 		dryrun_only = 1;
860Sstevel@tonic-gate 	}
870Sstevel@tonic-gate 	if ((options & MDCMD_FORCE) != 0) {
880Sstevel@tonic-gate 		newargv[newargc] = "-f";
890Sstevel@tonic-gate 		newargc++;
900Sstevel@tonic-gate 	}
910Sstevel@tonic-gate 	for (i = 0; i < argc; i++, newargc++)
920Sstevel@tonic-gate 		newargv[newargc] = argv[i];
930Sstevel@tonic-gate 	ret = meta_mn_send_command(*spp, newargc, newargv,
940Sstevel@tonic-gate 	    flags | MD_DRYRUN | MD_NOLOG, context, ep);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	if ((dryrun_only == 0) && (ret == 0)) {
970Sstevel@tonic-gate 		/*
980Sstevel@tonic-gate 		 * Do it for real now. Remove "-n" from the arguments and
990Sstevel@tonic-gate 		 * MD_DRYRUN from the flags. If we fail this time the master
1000Sstevel@tonic-gate 		 * must panic as the mddbs may be inconsistent.
1010Sstevel@tonic-gate 		 */
1020Sstevel@tonic-gate 		newargv[3] = ""; /* this was "-n" before */
1030Sstevel@tonic-gate 		ret = meta_mn_send_command(*spp, newargc, newargv,
1040Sstevel@tonic-gate 		    flags | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
1050Sstevel@tonic-gate 		    context,  ep);
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	free(newargv);
1090Sstevel@tonic-gate 	return (ret);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate static int
init_entries(mdsetname_t ** spp,md_tab_t * tabp,mdcmdopts_t options,uint_t flags,bool_t called_thru_rpc,md_error_t * ep)1130Sstevel@tonic-gate init_entries(
1140Sstevel@tonic-gate 	mdsetname_t	**spp,
1150Sstevel@tonic-gate 	md_tab_t	*tabp,
1160Sstevel@tonic-gate 	mdcmdopts_t	options,
1170Sstevel@tonic-gate 	uint_t		flags,
1180Sstevel@tonic-gate 	bool_t		called_thru_rpc,
1190Sstevel@tonic-gate 	md_error_t	*ep
1200Sstevel@tonic-gate )
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate 	uint_t		cnt = 0;
1230Sstevel@tonic-gate 	uint_t		line;
1240Sstevel@tonic-gate 	int		rval = 0;
1250Sstevel@tonic-gate 	int		ret;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	/* for all matching entries, which haven't already been done */
1280Sstevel@tonic-gate 	for (line = 0; (line < tabp->nlines); ++line) {
1290Sstevel@tonic-gate 		md_tab_line_t	*linep = &tabp->lines[line];
1301623Stw21770 		char		*uname = linep->argv[0];
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 		/* see if already done */
1330Sstevel@tonic-gate 		if (linep->flags != DO_AGAIN)
1340Sstevel@tonic-gate 			continue;
1350Sstevel@tonic-gate 
1361623Stw21770 		/* clear the metadev/hsp caches between inits */
1371623Stw21770 		metaflushmetanames();
1381623Stw21770 
1390Sstevel@tonic-gate 		/* try it */
1400Sstevel@tonic-gate 		if ((called_thru_rpc == FALSE) &&
1411623Stw21770 		    meta_is_mn_name(spp, uname, ep)) {
1420Sstevel@tonic-gate 			/*
1430Sstevel@tonic-gate 			 * MN set, send command to all nodes
1440Sstevel@tonic-gate 			 * Note that is sp is NULL, meta_is_mn_name() derives
1450Sstevel@tonic-gate 			 * sp from linep->argv which is the metadevice arg
1460Sstevel@tonic-gate 			 */
1470Sstevel@tonic-gate 			ret = mn_send_command(spp, linep->argc, linep->argv,
1480Sstevel@tonic-gate 			    options, flags, linep->context, ep);
1490Sstevel@tonic-gate 		} else {
1501623Stw21770 			char		*cname = NULL;
1511623Stw21770 
1521623Stw21770 			cname = meta_name_getname(spp, uname, META_DEVICE, ep);
1531623Stw21770 			if (cname == NULL) {
1541623Stw21770 				mde_perror(ep, "");
1551623Stw21770 				mdclrerror(ep);
1561623Stw21770 			} else {
1571623Stw21770 
1581623Stw21770 				ret = meta_init_name(spp, linep->argc,
1591623Stw21770 				    linep->argv, cname, options, ep);
1601623Stw21770 				Free(cname);
1611623Stw21770 
1621623Stw21770 				if (ret != 0) {
1631623Stw21770 					if (!(flags & MD_IGNORE_STDERR)) {
1641623Stw21770 					    mderrorextra(ep, linep->context);
1651623Stw21770 					    mde_perror(ep, "");
1661623Stw21770 					    rval = -1;
1671623Stw21770 					}
1681623Stw21770 					mdclrerror(ep);
1690Sstevel@tonic-gate 				}
1700Sstevel@tonic-gate 			}
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 		if (ret == 0) {
1730Sstevel@tonic-gate 			linep->flags = IS_DONE;
1740Sstevel@tonic-gate 			++cnt;
1750Sstevel@tonic-gate 		}
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/* return success */
1790Sstevel@tonic-gate 	if (rval != 0)
1800Sstevel@tonic-gate 		return (rval);
1810Sstevel@tonic-gate 	return (cnt);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate  * initialize all devices in set
1860Sstevel@tonic-gate  */
1870Sstevel@tonic-gate static int
init_all(mdsetname_t ** spp,mdcmdopts_t options,bool_t called_thru_rpc,md_error_t * ep)1880Sstevel@tonic-gate init_all(
1890Sstevel@tonic-gate 	mdsetname_t	**spp,
1900Sstevel@tonic-gate 	mdcmdopts_t	options,
1910Sstevel@tonic-gate 	bool_t		called_thru_rpc,
1920Sstevel@tonic-gate 	md_error_t	*ep
1930Sstevel@tonic-gate )
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	md_tab_t	*tabp = NULL;
1960Sstevel@tonic-gate 	size_t		setlen;
1970Sstevel@tonic-gate 	uint_t		more;
1980Sstevel@tonic-gate 	int		done;
1990Sstevel@tonic-gate 	int		eval = -1;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * Only take the lock if this is not a MN set
2030Sstevel@tonic-gate 	 * We can only enter this code for a MN set if we are the initiator
2040Sstevel@tonic-gate 	 * and in this case, we don't want to take locks.
2050Sstevel@tonic-gate 	 */
2060Sstevel@tonic-gate 	if (meta_is_mn_set((*spp), ep) == 0) {
2070Sstevel@tonic-gate 		/* grab set lock */
2080Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep)) {
2090Sstevel@tonic-gate 			mde_perror(ep, "");
2100Sstevel@tonic-gate 			mdclrerror(ep);
2110Sstevel@tonic-gate 			return (eval);
2120Sstevel@tonic-gate 		}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 		/* check for ownership */
2150Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0) {
2160Sstevel@tonic-gate 			mde_perror(ep, "");
2170Sstevel@tonic-gate 			mdclrerror(ep);
2180Sstevel@tonic-gate 			return (eval);
2190Sstevel@tonic-gate 		}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		/* lock is held across init_entries */
2220Sstevel@tonic-gate 		options |= MDCMD_NOLOCK;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/* get md.tab, preen entries */
2260Sstevel@tonic-gate 	if ((tabp = meta_tab_parse(NULL, ep)) == NULL) {
2270Sstevel@tonic-gate 		mde_perror(ep, "");
2280Sstevel@tonic-gate 		mdclrerror(ep);
2290Sstevel@tonic-gate 		return (eval);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2321623Stw21770 	setlen = strlen((*spp)->setname);
2330Sstevel@tonic-gate 	for (more = 0; (more < tabp->nlines); ++more) {
2340Sstevel@tonic-gate 		md_tab_line_t	*linep = &tabp->lines[more];
2350Sstevel@tonic-gate 		char		*cname = linep->cname;
2360Sstevel@tonic-gate 		char		*p;
2370Sstevel@tonic-gate 		size_t		len;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		/* better have args */
2400Sstevel@tonic-gate 		assert((linep->argc > 0) && (linep->argv[0] != NULL));
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		/* only do metadevices and hotspare pools in set */
2430Sstevel@tonic-gate 		if (linep->type & TAB_MD_HSP) {
2440Sstevel@tonic-gate 			if ((p = strrchr(cname, '/')) == NULL) {
2450Sstevel@tonic-gate 				len = 0;
2460Sstevel@tonic-gate 			} else {
2470Sstevel@tonic-gate 				len = p - cname;
2480Sstevel@tonic-gate 			}
2490Sstevel@tonic-gate 			if ((len == setlen) &&
2500Sstevel@tonic-gate 			    (strncmp(cname, (*spp)->setname, len) == 0)) {
2510Sstevel@tonic-gate 				linep->flags = DO_AGAIN;
2520Sstevel@tonic-gate 			} else {
2530Sstevel@tonic-gate 				linep->flags = DONT_DO;
2540Sstevel@tonic-gate 			}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		} else {
2570Sstevel@tonic-gate 			linep->flags = DONT_DO;
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	eval = 1;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	/* while more devices get made */
2640Sstevel@tonic-gate 	do {
2650Sstevel@tonic-gate 		done = init_entries(spp, tabp, options,
2660Sstevel@tonic-gate 		    MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep);
2670Sstevel@tonic-gate 	} while (done > 0);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/* now do it and report errors */
2700Sstevel@tonic-gate 	if (init_entries(spp, tabp, options, MD_RETRY_BUSY,
2710Sstevel@tonic-gate 	    called_thru_rpc, ep) >= 0)
2720Sstevel@tonic-gate 		eval = 0;	/* success */
2730Sstevel@tonic-gate 	mdclrerror(ep);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/* cleanup, return success */
2760Sstevel@tonic-gate out:
2770Sstevel@tonic-gate 	meta_tab_free(tabp);
2780Sstevel@tonic-gate 	return (eval);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate  * initialize named device or hotspare pool
2830Sstevel@tonic-gate  */
2840Sstevel@tonic-gate static int
init_name(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,int called_thru_rpc,md_error_t * ep)2850Sstevel@tonic-gate init_name(
2860Sstevel@tonic-gate 	mdsetname_t	**spp,
2870Sstevel@tonic-gate 	int		argc,
2880Sstevel@tonic-gate 	char		*argv[],
2890Sstevel@tonic-gate 	mdcmdopts_t	options,
2900Sstevel@tonic-gate 	int		called_thru_rpc,
2910Sstevel@tonic-gate 	md_error_t	*ep
2920Sstevel@tonic-gate )
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	md_tab_t	*tabp = NULL;
2950Sstevel@tonic-gate 	md_tab_line_t	*linep = NULL;
2960Sstevel@tonic-gate 	int		rval = -1;
2970Sstevel@tonic-gate 	int		ret;
2981623Stw21770 	char		*uname = argv[0];
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	/* look in md.tab */
3010Sstevel@tonic-gate 	if (argc == 1) {
3020Sstevel@tonic-gate 		/* get md.tab entries */
3030Sstevel@tonic-gate 		if ((tabp = meta_tab_parse(NULL, ep)) == NULL) {
3040Sstevel@tonic-gate 			if (! mdissyserror(ep, ENOENT))
3050Sstevel@tonic-gate 				return (-1);
3060Sstevel@tonic-gate 		}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		/* look in md.tab */
3091623Stw21770 		if ((linep = meta_tab_find(*spp, tabp, uname, TAB_MD_HSP))
3100Sstevel@tonic-gate 								!= NULL) {
3110Sstevel@tonic-gate 			argc = linep->argc;
3120Sstevel@tonic-gate 			argv = linep->argv;
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if ((called_thru_rpc == FALSE) &&
3171623Stw21770 	    meta_is_mn_name(spp, uname, ep)) {
3180Sstevel@tonic-gate 		/*
3190Sstevel@tonic-gate 		 * MN set, send command to all nodes
3200Sstevel@tonic-gate 		 */
3210Sstevel@tonic-gate 		ret = mn_send_command(spp, argc, argv, options,
3220Sstevel@tonic-gate 		    MD_DISP_STDERR, NO_CONTEXT_STRING, ep);
3231623Stw21770 	} else {
3241623Stw21770 		char		*cname = NULL;
3251623Stw21770 
3261623Stw21770 		cname = meta_name_getname(spp, uname, META_DEVICE, ep);
3271623Stw21770 		if (cname == NULL) {
3281623Stw21770 			goto out;
3291623Stw21770 		}
3301623Stw21770 
3311623Stw21770 		/* check for ownership */
3321623Stw21770 		if (meta_check_ownership(*spp, ep) != 0) {
3331623Stw21770 			Free(cname);
3341623Stw21770 			goto out;
3351623Stw21770 		}
3361623Stw21770 
3371623Stw21770 		ret = meta_init_name(spp, argc, argv, cname, options, ep);
3381623Stw21770 		Free(cname);
3391623Stw21770 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (ret != 0) {
3420Sstevel@tonic-gate 		if (linep != NULL)
3430Sstevel@tonic-gate 			mderrorextra(ep, linep->context);
3440Sstevel@tonic-gate 		goto out;
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 	rval = 0;	/* success */
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/* cleanup, return error */
3490Sstevel@tonic-gate out:
3500Sstevel@tonic-gate 	if (tabp != NULL)
3510Sstevel@tonic-gate 		meta_tab_free(tabp);
3520Sstevel@tonic-gate 	return (rval);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate  * print usage message
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate static void
usage(mdsetname_t * sp,int eval)3590Sstevel@tonic-gate usage(
3600Sstevel@tonic-gate 	mdsetname_t	*sp,
3610Sstevel@tonic-gate 	int		eval
3620Sstevel@tonic-gate )
3630Sstevel@tonic-gate {
3640Sstevel@tonic-gate #ifndef	lint
3650Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\
3660Sstevel@tonic-gate usage:	%s [-s setname] [-n] [-f] concat/stripe numstripes\n\
3670Sstevel@tonic-gate 		width component... [-i interlace]\n\
3680Sstevel@tonic-gate 		[width component... [-i interlace]] [-h hotspare_pool]\n\
3690Sstevel@tonic-gate 	%s [-s setname] [-n] [-f] mirror -m submirror...\n\
3700Sstevel@tonic-gate 		[read_options] [write_options] [pass_num]\n\
3710Sstevel@tonic-gate 	%s [-s setname] [-n] [-f] RAID -r component...\n\
3720Sstevel@tonic-gate 		[-i interlace] [-h hotspare_pool]\n\
3730Sstevel@tonic-gate 		[-k] [-o original_column_count]\n\
3740Sstevel@tonic-gate 	%s [-s setname] [-n] [-f] hotspare_pool [hotspare...]\n\
3750Sstevel@tonic-gate 	%s [-s setname] [-n] [-f] softpart -p [-A alignment]\n\
3760Sstevel@tonic-gate 		[-e] device size|all\n\
3770Sstevel@tonic-gate 	%s [-s setname] [-n] [-f] md.tab_entry\n\
3780Sstevel@tonic-gate 	%s [-s setname] [-n] [-f] -a\n\
3790Sstevel@tonic-gate 	%s -r\n"), myname, myname, myname, myname, myname, myname, myname,
3800Sstevel@tonic-gate 	    myname);
3810Sstevel@tonic-gate #endif	/* ! lint */
3820Sstevel@tonic-gate 	md_exit(sp, eval);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  * If we fail during the attempt to take the auto-take disksets
3870Sstevel@tonic-gate  * we need to tell the kernel to cleanup the in-core set struct
3880Sstevel@tonic-gate  * so that we have a chance to take the set again later.
3890Sstevel@tonic-gate  */
3900Sstevel@tonic-gate static void
auto_take_cleanup(mdsetname_t * sp,side_t sideno)3910Sstevel@tonic-gate auto_take_cleanup(mdsetname_t *sp, side_t sideno)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	mddb_config_t   c;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	(void) memset(&c, 0, sizeof (c));
3960Sstevel@tonic-gate 	c.c_setno = sp->setno;
3970Sstevel@tonic-gate 	c.c_sideno = sideno;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0) {
4000Sstevel@tonic-gate 		mde_perror(&c.c_mde, "auto_take_cleanup");
4010Sstevel@tonic-gate 		return;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate  * Take the diskset.
4070Sstevel@tonic-gate  *
4080Sstevel@tonic-gate  * This is a clean auto-take set, so do the work to take it.
4090Sstevel@tonic-gate  * This is a streamlined version of the code in meta_set_take.  We avoid the
4100Sstevel@tonic-gate  * need for talking to the rpc.metad since that can't run this early during the
4110Sstevel@tonic-gate  * boot.  We don't need to talk to the metad for this diskset since we're the
4120Sstevel@tonic-gate  * only host in the set.
4130Sstevel@tonic-gate  */
4140Sstevel@tonic-gate static void
take_set(md_set_record * sr)4150Sstevel@tonic-gate take_set(md_set_record *sr)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	mdsetname_t		sn;
4180Sstevel@tonic-gate 	md_drive_desc		*dd;
4190Sstevel@tonic-gate 	md_error_t		error = mdnullerror;
4200Sstevel@tonic-gate 	md_replicalist_t	*rlp = NULL;
4210Sstevel@tonic-gate 	md_replicalist_t	*rl;
4220Sstevel@tonic-gate 	daddr_t			nblks = 0;
4230Sstevel@tonic-gate 	md_drive_record		*dr;
4240Sstevel@tonic-gate 	side_t			sideno;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	/*
4270Sstevel@tonic-gate 	 * Several of the functions we call take a sp param so
4280Sstevel@tonic-gate 	 * construct one from the set record.
4290Sstevel@tonic-gate 	 */
4300Sstevel@tonic-gate 	sn.setname = sr->sr_setname;
4310Sstevel@tonic-gate 	sn.setno = sr->sr_setno;
4320Sstevel@tonic-gate 	sn.setdesc = sr2setdesc(sr);
4330Sstevel@tonic-gate 	sn.lockfd = MD_NO_LOCK;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (sr->sr_flags & MD_SR_MB_DEVID)
4360Sstevel@tonic-gate 		dd = metaget_drivedesc(&sn, MD_BASICNAME_OK | PRINT_FAST,
4370Sstevel@tonic-gate 		    &error);
4380Sstevel@tonic-gate 	else
4390Sstevel@tonic-gate 		dd = metaget_drivedesc(&sn, MD_BASICNAME_OK, &error);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (dd == NULL) {
4420Sstevel@tonic-gate 	    mde_perror(&error, "");
4430Sstevel@tonic-gate 	    mdclrerror(&error);
4440Sstevel@tonic-gate 	    return;
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/*
4480Sstevel@tonic-gate 	 * Skip call to tk_own_bydd.  This talks to rpc.metamhd (which we can't
4490Sstevel@tonic-gate 	 * do yet) and is not needed for auto-take disksets since we are not
4500Sstevel@tonic-gate 	 * doing SCSI reservations on these drives.
4510Sstevel@tonic-gate 	 */
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	if (setup_db_bydd(&sn, dd, 0, &error) != 0) {
4540Sstevel@tonic-gate 	    if (! mdismddberror(&error, MDE_DB_ACCOK) &&
4550Sstevel@tonic-gate 		! mdismddberror(&error, MDE_DB_TAGDATA)) {
4560Sstevel@tonic-gate 		/*
4570Sstevel@tonic-gate 		 * Skip call to rel_own_bydd since that really just
4580Sstevel@tonic-gate 		 * calls rpc.metamhd which we don't need to do,
4590Sstevel@tonic-gate 		 * so there really isn't anything to rollback here.
4600Sstevel@tonic-gate 		 */
4610Sstevel@tonic-gate 		mde_perror(&error, "");
4620Sstevel@tonic-gate 		mdclrerror(&error);
4630Sstevel@tonic-gate 		return;
4640Sstevel@tonic-gate 	    }
4650Sstevel@tonic-gate 	    mdclrerror(&error);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	if ((sideno = getmyside(&sn, &error)) == MD_SIDEWILD) {
4690Sstevel@tonic-gate 	    mde_perror(&error, "");
4700Sstevel@tonic-gate 	    return;
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if (snarf_set(&sn, FALSE, &error) != 0) {
4740Sstevel@tonic-gate 	    if (mdismddberror(&error, MDE_DB_STALE) ||
4750Sstevel@tonic-gate 		mdismddberror(&error, MDE_DB_TAGDATA) ||
4760Sstevel@tonic-gate 		! mdismddberror(&error, MDE_DB_NODB) &&
4770Sstevel@tonic-gate 		! mdismddberror(&error, MDE_DB_NOTOWNER)) {
4780Sstevel@tonic-gate 		/*
4790Sstevel@tonic-gate 		 * rollback
4800Sstevel@tonic-gate 		 * Normally MDE_DB_STALE or MDE_DB_TAGDATA
4810Sstevel@tonic-gate 		 * would still keep the set but in this case we don't
4820Sstevel@tonic-gate 		 * want to do that.  This will probably result in the
4830Sstevel@tonic-gate 		 * boot going in to single-user since we won't have the
4840Sstevel@tonic-gate 		 * set so any attempted mounts using the set's metadevices
4850Sstevel@tonic-gate 		 * will fail.  However, that is a "good thing" so the
4860Sstevel@tonic-gate 		 * sysadmin can fix the set.  Normally they would see
4870Sstevel@tonic-gate 		 * all of these problems when they ran the take and be
4880Sstevel@tonic-gate 		 * able to immediately fix the problem.
4890Sstevel@tonic-gate 		 */
4900Sstevel@tonic-gate 		mde_perror(&error, "");
4910Sstevel@tonic-gate 		auto_take_cleanup(&sn, sideno);
4920Sstevel@tonic-gate 		return;
4930Sstevel@tonic-gate 	    }
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	/*
4970Sstevel@tonic-gate 	 * Call metareplicalist and upd_dr_dbinfo.
4980Sstevel@tonic-gate 	 * Most of that code is only needed to synchronize amongst the multiple
4990Sstevel@tonic-gate 	 * hosts in a set, which is not applicable in our case.  But we do a
5000Sstevel@tonic-gate 	 * subset here to handle the case when the user had been
5010Sstevel@tonic-gate 	 * adding/deleting/balancing mddbs when this node panic'd.  We are
5020Sstevel@tonic-gate 	 * synchronizing the ondisk mddbs to the list of drive records stored
5030Sstevel@tonic-gate 	 * in the local mddb.
5040Sstevel@tonic-gate 	 */
5050Sstevel@tonic-gate 	if (metareplicalist(&sn, (MD_BASICNAME_OK | PRINT_FAST), &rlp, &error)
5060Sstevel@tonic-gate 	    < 0) {
5070Sstevel@tonic-gate 	    /* rollback */
5080Sstevel@tonic-gate 	    mde_perror(&error, "");
5090Sstevel@tonic-gate 	    auto_take_cleanup(&sn, sideno);
5100Sstevel@tonic-gate 	    return;
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	 * The following code is equivalent to upd_dr_dbinfo for syncronizing
5150Sstevel@tonic-gate 	 * the local host only.  That function is normally run through the
5160Sstevel@tonic-gate 	 * metad with a local and daemon side but we'll do all of the work
5170Sstevel@tonic-gate 	 * here.
5180Sstevel@tonic-gate 	 */
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	/* find the smallest existing replica */
5210Sstevel@tonic-gate 	for (rl = rlp; rl != NULL; rl = rl->rl_next) {
5220Sstevel@tonic-gate 	    md_replica_t *r;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	    r = rl->rl_repp;
5250Sstevel@tonic-gate 	    nblks = ((nblks == 0) ? r->r_nblk : min(r->r_nblk, nblks));
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	if (nblks <= 0)
5290Sstevel@tonic-gate 	    nblks = MD_DBSIZE;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	for (dr = sr->sr_drivechain; dr; dr = dr->dr_next) {
5320Sstevel@tonic-gate 	    int			dbcnt;
5330Sstevel@tonic-gate 	    mddrivename_t	*dnp;
5340Sstevel@tonic-gate 	    md_replicalist_t	*rl;
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 		/*
5370Sstevel@tonic-gate 		 * The cname style for dnp and replica list will be same since
5380Sstevel@tonic-gate 		 * both use the the same flags MD_BASICNAME_OK|PRINT_FAST which
5390Sstevel@tonic-gate 		 * will always provide the cached value.
5400Sstevel@tonic-gate 		 */
5410Sstevel@tonic-gate 	    if ((dnp = metadrivename_withdrkey(&sn, sideno, dr->dr_key,
5420Sstevel@tonic-gate 		MD_BASICNAME_OK | PRINT_FAST, &error)) == NULL) {
5430Sstevel@tonic-gate 		mde_perror(&error, "");
5440Sstevel@tonic-gate 		metafreereplicalist(rlp);
5450Sstevel@tonic-gate 		auto_take_cleanup(&sn, sideno);
5460Sstevel@tonic-gate 		return;
5470Sstevel@tonic-gate 	    }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	    dbcnt = 0;
5500Sstevel@tonic-gate 	    /* see how many replicas are on this drive */
5510Sstevel@tonic-gate 	    for (rl = rlp; rl != NULL; rl = rl->rl_next) {
5520Sstevel@tonic-gate 		if (strcmp(rl->rl_repp->r_namep->drivenamep->cname, dnp->cname)
5530Sstevel@tonic-gate 		    == 0)
5540Sstevel@tonic-gate 		    dbcnt++;
5550Sstevel@tonic-gate 	    }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	    /* Adjust the fields in the copy */
5580Sstevel@tonic-gate 	    dr->dr_dbcnt = dbcnt;
5590Sstevel@tonic-gate 	    dr->dr_dbsize = dbcnt > 0 ? nblks : 0;
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/*
5630Sstevel@tonic-gate 	 * If the set doesn't have the MD_SR_MB_DEVID bit set, i.e
5640Sstevel@tonic-gate 	 * the drives in the set don't have the device id information,
5650Sstevel@tonic-gate 	 * then stick it in if possible.
5660Sstevel@tonic-gate 	 *
5670Sstevel@tonic-gate 	 * If updating the master block fails for whatever reason, it's
5680Sstevel@tonic-gate 	 * okay. It just means the disk(s) in the diskset won't be self
5690Sstevel@tonic-gate 	 * identifying.
5700Sstevel@tonic-gate 	 */
5710Sstevel@tonic-gate 	if (!(sr->sr_flags & MD_SR_MB_DEVID)) {
5720Sstevel@tonic-gate 		if (meta_update_mb(&sn, dd, &error) == 0) {
5730Sstevel@tonic-gate 			sr->sr_flags |= MD_SR_MB_DEVID;
5740Sstevel@tonic-gate 			mdclrerror(&error);
5750Sstevel@tonic-gate 		}
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	commitset(sr, FALSE, &error);
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	metafreereplicalist(rlp);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * This finishes up the logical equivalent of meta_set_take.
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	if (meta_resync_all(&sn, MD_DEF_RESYNC_BUF_SIZE, &error) != 0) {
5860Sstevel@tonic-gate 	    mde_perror(&error, "");
5870Sstevel@tonic-gate 	    mdclrerror(&error);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * Take the disksets that are marked to be taken at boot time.
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate static void
auto_take_sets()5950Sstevel@tonic-gate auto_take_sets()
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	int		max_sets;
5980Sstevel@tonic-gate 	int		i;
5990Sstevel@tonic-gate 	md_error_t	error = mdnullerror;
6000Sstevel@tonic-gate 	char		*hostname;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if ((max_sets = get_max_sets(&error)) == 0)
6030Sstevel@tonic-gate 	    return;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	if (!mdisok(&error)) {
6060Sstevel@tonic-gate 	    mde_perror(&error, "");
6070Sstevel@tonic-gate 	    return;
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	/* set up so auto-take errors also go to syslog */
6110Sstevel@tonic-gate 	openlog("metainit", LOG_ODELAY, LOG_USER);
6120Sstevel@tonic-gate 	metasyslog = 1;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	hostname = mynode();
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	/*
6170Sstevel@tonic-gate 	 * For each possible set number (skip set 0 which is the unnamed local
6180Sstevel@tonic-gate 	 * set), see if we really have a diskset.  If so, check if auto-take
6190Sstevel@tonic-gate 	 * is enabled.
6200Sstevel@tonic-gate 	 *
6210Sstevel@tonic-gate 	 * In order to take the set it must have drives and it must not be
6220Sstevel@tonic-gate 	 * stuck in mid-add.  The sr_validate routine within rpc.metad will
6230Sstevel@tonic-gate 	 * delete sets that are in mid-add when it runs.
6240Sstevel@tonic-gate 	 */
6250Sstevel@tonic-gate 	for (i = 1; i < max_sets; i++) {
6260Sstevel@tonic-gate 	    md_set_record	*sr;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	    if ((sr = metad_getsetbynum(i, &error)) == NULL) {
6290Sstevel@tonic-gate 		mdclrerror(&error);
6300Sstevel@tonic-gate 		continue;
6310Sstevel@tonic-gate 	    }
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	    if (sr->sr_flags & MD_SR_AUTO_TAKE && !(sr->sr_flags & MD_SR_ADD)) {
6340Sstevel@tonic-gate 		int	j;
6350Sstevel@tonic-gate 		int	cnt = 0;
6360Sstevel@tonic-gate 		int	host_mismatch = 0;
6370Sstevel@tonic-gate 		int	take = 0;
6380Sstevel@tonic-gate 		md_drive_record	*dr;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		/* check for host renames or multiple hosts in set */
6410Sstevel@tonic-gate 		for (j = 0; j < MD_MAXSIDES; j++) {
6420Sstevel@tonic-gate 		    /* Skip empty slots */
6430Sstevel@tonic-gate 		    if (sr->sr_nodes[j][0] == '\0')
6440Sstevel@tonic-gate 			continue;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 		    cnt++;
6470Sstevel@tonic-gate 		    if (strcmp(sr->sr_nodes[j], hostname) != 0)
6480Sstevel@tonic-gate 			host_mismatch = 1;
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		/* paranoid check that we're the only host in the set */
6520Sstevel@tonic-gate 		if (cnt > 1) {
6530Sstevel@tonic-gate 			md_eprintf(gettext(
6540Sstevel@tonic-gate 		"diskset %s: auto-take enabled and multiple hosts in set\n"),
6550Sstevel@tonic-gate 			    sr->sr_setname);
6560Sstevel@tonic-gate 			continue;
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		if (host_mismatch) {
6600Sstevel@tonic-gate 			/* The host was renamed, repair the set. */
6610Sstevel@tonic-gate 			for (j = 0; j < MD_MAXSIDES; j++) {
6620Sstevel@tonic-gate 				/* Skip empty slots */
6630Sstevel@tonic-gate 				if (sr->sr_nodes[j][0] == '\0')
6640Sstevel@tonic-gate 					continue;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 				(void) strncpy(sr->sr_nodes[j], hostname,
6670Sstevel@tonic-gate 				    sizeof (sr->sr_nodes[j]));
6680Sstevel@tonic-gate 				commitset(sr, FALSE, &error);
6690Sstevel@tonic-gate 				if (!mdisok(&error)) {
6700Sstevel@tonic-gate 					mde_perror(&error, "");
6710Sstevel@tonic-gate 					mdclrerror(&error);
6720Sstevel@tonic-gate 				} else {
6730Sstevel@tonic-gate 					md_eprintf(gettext(
6740Sstevel@tonic-gate 			"new hostname %s, update auto-take diskset %s\n"),
6750Sstevel@tonic-gate 						hostname, sr->sr_setname);
6760Sstevel@tonic-gate 				}
6770Sstevel@tonic-gate 				break;
6780Sstevel@tonic-gate 			}
6790Sstevel@tonic-gate 		}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		/* set must have at least one drive to be taken */
6820Sstevel@tonic-gate 		for (dr = sr->sr_drivechain; dr != NULL; dr = dr->dr_next) {
6830Sstevel@tonic-gate 			/* ignore drives in mid-add */
6840Sstevel@tonic-gate 			if (!(dr->dr_flags & MD_DR_ADD)) {
6850Sstevel@tonic-gate 			    take = 1;
6860Sstevel@tonic-gate 			    break;
6870Sstevel@tonic-gate 			}
6880Sstevel@tonic-gate 		}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 		if (take)
6910Sstevel@tonic-gate 			take_set(sr);
6920Sstevel@tonic-gate 		else
6930Sstevel@tonic-gate 			md_eprintf(gettext(
6940Sstevel@tonic-gate 		"diskset %s: auto-take enabled but set has no drives\n"),
6950Sstevel@tonic-gate 			    sr->sr_setname);
6960Sstevel@tonic-gate 	    }
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate /*
7010Sstevel@tonic-gate  * mainline. crack command line arguments.
7020Sstevel@tonic-gate  */
7030Sstevel@tonic-gate int
main(int argc,char * argv[])7040Sstevel@tonic-gate main(
7050Sstevel@tonic-gate 	int		argc,
7060Sstevel@tonic-gate 	char		*argv[]
7070Sstevel@tonic-gate )
7080Sstevel@tonic-gate {
7091623Stw21770 	char		*sname = MD_LOCAL_NAME;
7100Sstevel@tonic-gate 	mdsetname_t	*sp = NULL;
7110Sstevel@tonic-gate 	enum action {
7120Sstevel@tonic-gate 		NONE,
7130Sstevel@tonic-gate 		INIT,
7140Sstevel@tonic-gate 		ALL
7150Sstevel@tonic-gate 	}		todo = NONE;
7160Sstevel@tonic-gate 	mdcmdopts_t	options = (MDCMD_DOIT | MDCMD_PRINT);
7170Sstevel@tonic-gate 	int		c;
7180Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
7190Sstevel@tonic-gate 	md_error_t	*ep = &status;
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	md_error_t	dummystatus = mdnullerror;
7220Sstevel@tonic-gate 	md_error_t	*dummyep = &dummystatus;
7230Sstevel@tonic-gate 	int		eval = 1;
7240Sstevel@tonic-gate 	int		error;
7250Sstevel@tonic-gate 	bool_t		called_thru_rpc = FALSE;
7260Sstevel@tonic-gate 	char		*cp;
727*7044Smk117520 	pid_t		pid;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
7310Sstevel@tonic-gate 	 * with messages to ouput.  Just in case we're not in a build
7320Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
7330Sstevel@tonic-gate 	 * something.
7340Sstevel@tonic-gate 	 */
7350Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
7360Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
7370Sstevel@tonic-gate #endif
7380Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
7390Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
7400Sstevel@tonic-gate 	if ((cp = strstr(argv[0], ".rpc_call")) != NULL) {
7410Sstevel@tonic-gate 		*cp = '\0'; /* cut off ".rpc_call" */
7420Sstevel@tonic-gate 		called_thru_rpc = TRUE;
7430Sstevel@tonic-gate 	} else {
7440Sstevel@tonic-gate 		if (sdssc_bind_library() == SDSSC_OKAY)
7450Sstevel@tonic-gate 			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
7460Sstevel@tonic-gate 						&error) == SDSSC_PROXY_DONE)
7470Sstevel@tonic-gate 				exit(error);
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/* initialize */
7510Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0 ||
7520Sstevel@tonic-gate 			meta_check_root(ep) != 0) {
7530Sstevel@tonic-gate 		mde_perror(ep, "");
7540Sstevel@tonic-gate 		md_exit(sp, 1);
7550Sstevel@tonic-gate 	}
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/* parse args */
7580Sstevel@tonic-gate 	optind = 1;
7590Sstevel@tonic-gate 	opterr = 1;
7600Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "afhnrs:?")) != -1) {
7610Sstevel@tonic-gate 		switch (c) {
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 		/* help */
7640Sstevel@tonic-gate 		case 'h':
7650Sstevel@tonic-gate 			usage(sp, 0);
7660Sstevel@tonic-gate 			break;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		/* set name */
7690Sstevel@tonic-gate 		case 's':
7700Sstevel@tonic-gate 			sname = optarg;
7710Sstevel@tonic-gate 			break;
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 		/* all devices in md.tab */
7740Sstevel@tonic-gate 		case 'a':
7750Sstevel@tonic-gate 			if (todo != NONE)
7760Sstevel@tonic-gate 				usage(sp, 1);
7770Sstevel@tonic-gate 			todo = ALL;
7780Sstevel@tonic-gate 			options |= MDCMD_ALLOPTION;
7790Sstevel@tonic-gate 			break;
7800Sstevel@tonic-gate 		/* check for validity, but don't really init */
7810Sstevel@tonic-gate 		case 'n':
7820Sstevel@tonic-gate 			options &= ~MDCMD_DOIT;
7830Sstevel@tonic-gate 			break;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 		/* for recovery */
7860Sstevel@tonic-gate 		case 'r':
7870Sstevel@tonic-gate 			if (todo != NONE)
7880Sstevel@tonic-gate 				usage(sp, 1);
7890Sstevel@tonic-gate 			todo = INIT;
7900Sstevel@tonic-gate 			break;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		/* mounted and swapped components are OK */
7930Sstevel@tonic-gate 		case 'f':
7940Sstevel@tonic-gate 			options |= MDCMD_FORCE;
7950Sstevel@tonic-gate 			break;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 		case '?':
7980Sstevel@tonic-gate 			if (optopt == '?')
7990Sstevel@tonic-gate 				usage(sp, 0);
8000Sstevel@tonic-gate 			/*FALLTHROUGH*/
8010Sstevel@tonic-gate 		default:
8020Sstevel@tonic-gate 			usage(sp, 1);
8030Sstevel@tonic-gate 			break;
8040Sstevel@tonic-gate 		}
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 
8071623Stw21770 	/* sname is MD_LOCAL_NAME if not specified on the command line */
8081623Stw21770 	if ((sp = metasetname(sname, ep)) == NULL) {
8091623Stw21770 		mde_perror(ep, "");
8101623Stw21770 		md_exit(sp, 1);
8110Sstevel@tonic-gate 	}
8121623Stw21770 
8130Sstevel@tonic-gate 	argc -= optind;
8140Sstevel@tonic-gate 	argv += optind;
8150Sstevel@tonic-gate 	if (todo == NONE) {
8160Sstevel@tonic-gate 		if (argc <= 0) {
8170Sstevel@tonic-gate 			usage(sp, 1);
8180Sstevel@tonic-gate 		}
8190Sstevel@tonic-gate 	} else if (argc > 0) {
8200Sstevel@tonic-gate 		usage(sp, 1);
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	/* setup database locations */
8250Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
8260Sstevel@tonic-gate 		mde_perror(ep, "");
8270Sstevel@tonic-gate 		if (mdismddberror(ep, MDE_DB_STALE))
8280Sstevel@tonic-gate 			md_exit(sp, 66);
8290Sstevel@tonic-gate 		if (! mdiserror(ep, MDE_MDDB_CKSUM))	/* relatively benign */
8300Sstevel@tonic-gate 			md_exit(sp, 1);
8310Sstevel@tonic-gate 	}
8320Sstevel@tonic-gate 	if (todo == INIT) {		/* load and take auto-take sets */
8330Sstevel@tonic-gate 		auto_take_sets();
834*7044Smk117520 
835*7044Smk117520 		/*
836*7044Smk117520 		 * During the boot sequence we need to update the mediator
837*7044Smk117520 		 * records, however this depends upon the rpc.metamedd
838*7044Smk117520 		 * running. So, in order to not introduce a delay in the
839*7044Smk117520 		 * boot time, fork a new process to do this work in the
840*7044Smk117520 		 * background.
841*7044Smk117520 		 */
842*7044Smk117520 		pid = fork1();
843*7044Smk117520 		if (pid == (pid_t)-1) {
844*7044Smk117520 			/*
845*7044Smk117520 			 * We could not fork a child process to udpate mediator
846*7044Smk117520 			 * information on this node. There is no need to panic.
847*7044Smk117520 			 * We shall simply return 1.
848*7044Smk117520 			 */
849*7044Smk117520 			mde_perror(ep, "Could not fork a child process to"
850*7044Smk117520 			    " update mediator record");
851*7044Smk117520 			md_exit(sp, 1);
852*7044Smk117520 		} else if (pid == (pid_t)0) {
853*7044Smk117520 			/* child */
854*7044Smk117520 			if (meta_mediator_info_from_file(NULL, 0, ep) == 1) {
855*7044Smk117520 				/*
856*7044Smk117520 				 * No need to print any error messages.
857*7044Smk117520 				 * All the errors messages are printed in the
858*7044Smk117520 				 * library routine itself.
859*7044Smk117520 				 */
860*7044Smk117520 				md_exit(sp, 1);
861*7044Smk117520 			} else {
862*7044Smk117520 				md_exit(sp, 0);
863*7044Smk117520 			}
864*7044Smk117520 		} else {
865*7044Smk117520 			/* Parent process */
866*7044Smk117520 			md_exit(sp, 0);
867*7044Smk117520 		}
8680Sstevel@tonic-gate 	} else if (todo == ALL) {	/* initialize all devices in md.tab */
8690Sstevel@tonic-gate 		eval = init_all(&sp, options, called_thru_rpc, ep);
8700Sstevel@tonic-gate 	} else {			/* initialize the named device */
8710Sstevel@tonic-gate 		eval = 0;
8720Sstevel@tonic-gate 		if (init_name(&sp, argc, argv, options, called_thru_rpc,
8730Sstevel@tonic-gate 		    ep) != 0) {
8740Sstevel@tonic-gate 			/*
8750Sstevel@tonic-gate 			 * If we're dealing with MN metadevices and we are
8760Sstevel@tonic-gate 			 * directly called, then the appropriate error message
8770Sstevel@tonic-gate 			 * has already been displayed. So just exit.
8780Sstevel@tonic-gate 			 */
8790Sstevel@tonic-gate 			if (meta_is_mn_set(sp, dummyep) && (!called_thru_rpc)) {
8800Sstevel@tonic-gate 				md_exit(sp, 1);
8810Sstevel@tonic-gate 			}
8820Sstevel@tonic-gate 			mde_perror(ep, "");
8830Sstevel@tonic-gate 			mdclrerror(ep);
8840Sstevel@tonic-gate 			eval = 1;
8850Sstevel@tonic-gate 			goto nomdcf;
8860Sstevel@tonic-gate 		}
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate domdcf:
8900Sstevel@tonic-gate 	/* update md.cf, return success */
8910Sstevel@tonic-gate 	if (meta_update_md_cf(sp, ep) != 0) {
8920Sstevel@tonic-gate 		mde_perror(ep, "");
8930Sstevel@tonic-gate 		eval = 1;
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate nomdcf:
8970Sstevel@tonic-gate 	md_exit(sp, eval);
8980Sstevel@tonic-gate 	/*NOTREACHED*/
8990Sstevel@tonic-gate 	return (eval);
9000Sstevel@tonic-gate }
901