xref: /onnv-gate/usr/src/cmd/lvm/util/metaimport.c (revision 11053:f33a1c7f3155)
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
51945Sjeanm  * Common Development and Distribution License (the "License").
61945Sjeanm  * 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*11053SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Utility to import SVM disksets into an active SVM configuration.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <assert.h>
310Sstevel@tonic-gate #include <strings.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <meta.h>
340Sstevel@tonic-gate #include <sys/utsname.h>
350Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
360Sstevel@tonic-gate #include <sys/lvm/md_names.h>
370Sstevel@tonic-gate #include <sdssc.h>
380Sstevel@tonic-gate 
391945Sjeanm static md_im_drive_info_t	*overlap_disks;
400Sstevel@tonic-gate 
410Sstevel@tonic-gate static void
usage(mdsetname_t * sp,char * string)420Sstevel@tonic-gate usage(mdsetname_t *sp, char *string)
430Sstevel@tonic-gate {
440Sstevel@tonic-gate 	if ((string != NULL) && (*string != '\0'))
450Sstevel@tonic-gate 		md_eprintf("%s\n", string);
460Sstevel@tonic-gate 
470Sstevel@tonic-gate 	(void) fprintf(stderr,
480Sstevel@tonic-gate 	    "%s:\t%s -s setname [-n] [-f] [-v] [%s...]\n",
490Sstevel@tonic-gate 	    gettext("usage"), myname, gettext("disk"));
500Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -r [%s...]\n",
510Sstevel@tonic-gate 	    myname, gettext("disk"));
520Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -?\n", myname);
530Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -V\n", myname);
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	md_exit(sp, (string == NULL) ? 0 : 1);
560Sstevel@tonic-gate }
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static void
print_version(mdsetname_t * sp)590Sstevel@tonic-gate print_version(mdsetname_t *sp)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	struct utsname curname;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	if (uname(&curname) == -1) {
640Sstevel@tonic-gate 		md_eprintf("%s\n", strerror(errno));
650Sstevel@tonic-gate 		md_exit(sp, 1);
660Sstevel@tonic-gate 	}
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	(void) fprintf(stderr, "%s %s\n", myname, curname.version);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	md_exit(sp, 0);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * Returns 0 if there is no overlap, 1 otherwise
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate static int
set_disk_overlap(md_im_set_desc_t * misp)770Sstevel@tonic-gate set_disk_overlap(md_im_set_desc_t *misp)
780Sstevel@tonic-gate {
791945Sjeanm 	md_im_set_desc_t	*next, *isp = misp;
801945Sjeanm 	md_im_drive_info_t	*set_dr, *next_set_dr, **chain;
811945Sjeanm 	int			is_overlap = 0;
821945Sjeanm 	md_im_drive_info_t	*good_disk = NULL;
831945Sjeanm 	md_im_drive_info_t	*d;
841945Sjeanm 	md_timeval32_t		gooddisktime;
851945Sjeanm 	int			disk_not_available = 0;
861945Sjeanm 	/*
871945Sjeanm 	 * There are 2 ways we could get an "overlap" disk.
881945Sjeanm 	 * One is if the ctd's are the same. The other is if
891945Sjeanm 	 * the setcreatetimestamp on the disk doesn't agree with the
901945Sjeanm 	 * "good" disk in the set. However, if we have a disk that is
911945Sjeanm 	 * unavailable and the other instance of the ctd is available we
921945Sjeanm 	 * really don't have a conflict. It's just that the unavailable ctd
931945Sjeanm 	 * is it's "old" location and the available instance is a current
941945Sjeanm 	 * location.
951945Sjeanm 	 */
960Sstevel@tonic-gate 	for (; isp != NULL; isp = isp->mis_next) {
970Sstevel@tonic-gate 	    for (next = isp->mis_next; next != NULL; next = next->mis_next) {
980Sstevel@tonic-gate 		for (set_dr = isp->mis_drives; set_dr != NULL;
991945Sjeanm 		    set_dr = set_dr->mid_next) {
1001945Sjeanm 		    if (set_dr->mid_available == MD_IM_DISK_NOT_AVAILABLE)
1011945Sjeanm 			disk_not_available = 1;
1021945Sjeanm 		    else
1031945Sjeanm 			disk_not_available = 0;
1041945Sjeanm 		    for (next_set_dr = next->mis_drives; next_set_dr != NULL;
1051945Sjeanm 			next_set_dr = next_set_dr->mid_next) {
1061945Sjeanm 			if (disk_not_available &&
1071945Sjeanm 			    (next_set_dr->mid_available
1081945Sjeanm 			    == MD_IM_DISK_AVAILABLE))
1091945Sjeanm 				continue;
1101945Sjeanm 			else if (!disk_not_available &&
1111945Sjeanm 			    (next_set_dr->mid_available ==
1121945Sjeanm 			    MD_IM_DISK_NOT_AVAILABLE))
1131945Sjeanm 				continue;
1141945Sjeanm 			if (strcmp(set_dr->mid_dnp->cname,
1151945Sjeanm 			    next_set_dr->mid_dnp->cname) == 0) {
1160Sstevel@tonic-gate 				/*
1171945Sjeanm 				 * Chain it, skip if
1181945Sjeanm 				 * already there
1190Sstevel@tonic-gate 				 */
1200Sstevel@tonic-gate 				if (overlap_disks == NULL) {
1210Sstevel@tonic-gate 					set_dr->overlap = NULL;
1221945Sjeanm 					set_dr->overlapped_disk = 1;
1231945Sjeanm 					next_set_dr->overlapped_disk = 1;
1240Sstevel@tonic-gate 					overlap_disks = set_dr;
1250Sstevel@tonic-gate 				} else {
1260Sstevel@tonic-gate 				    for (chain = &overlap_disks;
1270Sstevel@tonic-gate 					*chain != NULL;
1280Sstevel@tonic-gate 					chain = &(*chain)->overlap) {
1290Sstevel@tonic-gate 					if (strcmp(set_dr->mid_dnp->cname,
1301945Sjeanm 					    (*chain)->mid_dnp->cname) == 0)
1310Sstevel@tonic-gate 						break;
1320Sstevel@tonic-gate 				    }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 				    if (*chain == NULL) {
1350Sstevel@tonic-gate 					*chain = set_dr;
1360Sstevel@tonic-gate 					set_dr->overlap = NULL;
1371945Sjeanm 					set_dr->overlapped_disk = 1;
1381945Sjeanm 					next_set_dr->overlapped_disk = 1;
1390Sstevel@tonic-gate 				    }
1400Sstevel@tonic-gate 				}
1410Sstevel@tonic-gate 				if (!is_overlap)
1420Sstevel@tonic-gate 					is_overlap = 1;
1430Sstevel@tonic-gate 			}
1441945Sjeanm 		    }
1450Sstevel@tonic-gate 		}
1460Sstevel@tonic-gate 	    }
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1491945Sjeanm 	for (isp = misp; isp != NULL; isp = isp->mis_next) {
1501945Sjeanm 		good_disk = pick_good_disk(isp);
1511945Sjeanm 		if (good_disk == NULL) {
1521945Sjeanm 			/* didn't find a good disk */
1531945Sjeanm 			continue;
1541945Sjeanm 		}
1551945Sjeanm 		gooddisktime = good_disk->mid_setcreatetimestamp;
1561945Sjeanm 		for (d = isp->mis_drives; d != NULL; d = d->mid_next) {
1571945Sjeanm 			if (d->mid_available == MD_IM_DISK_NOT_AVAILABLE)
1581945Sjeanm 				continue;
1591945Sjeanm 			/*
1601945Sjeanm 			 * If the disk doesn't have the same set creation
1611945Sjeanm 			 * time as the designated "good disk" we have a
1621945Sjeanm 			 * time conflict/overlap situation. Mark the disk
1631945Sjeanm 			 * as such.
1641945Sjeanm 			 */
1651945Sjeanm 			if ((gooddisktime.tv_usec !=
1661945Sjeanm 			    d->mid_setcreatetimestamp.tv_usec) ||
1671945Sjeanm 			    (gooddisktime.tv_sec !=
1681945Sjeanm 			    d->mid_setcreatetimestamp.tv_sec)) {
1691945Sjeanm 				d->overlapped_disk = 1;
1701945Sjeanm 				if (overlap_disks == NULL) {
1711945Sjeanm 					d->overlap = NULL;
1721945Sjeanm 					d->overlapped_disk = 1;
1731945Sjeanm 					overlap_disks = d;
1741945Sjeanm 				} else {
1751945Sjeanm 					for (chain = &overlap_disks;
1761945Sjeanm 					    *chain != NULL;
1771945Sjeanm 					    chain = &(*chain)->overlap) {
1781945Sjeanm 						if (strcmp(d->mid_dnp->cname,
1791945Sjeanm 						    (*chain)->mid_dnp->cname)
1801945Sjeanm 						    == 0) {
1811945Sjeanm 							break;
1821945Sjeanm 						}
1831945Sjeanm 					}
1841945Sjeanm 
1851945Sjeanm 					if (*chain == NULL) {
1861945Sjeanm 						*chain = d;
1871945Sjeanm 						d->overlap = NULL;
1881945Sjeanm 						d->overlapped_disk = 1;
1891945Sjeanm 					}
1901945Sjeanm 				}
1911945Sjeanm 				if (!is_overlap)
1921945Sjeanm 					is_overlap = 1;
1931945Sjeanm 			}
1941945Sjeanm 		}
1951945Sjeanm 	}
1960Sstevel@tonic-gate 	return (is_overlap);
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate static void
report_overlap_recommendation()2000Sstevel@tonic-gate report_overlap_recommendation()
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	mddb_mb_t		*mbp;
2030Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
2040Sstevel@tonic-gate 	md_error_t		*ep = &status;
2050Sstevel@tonic-gate 	md_im_drive_info_t	*d;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	(void) fprintf(stdout, "%s\n", gettext("Warning:  The following disks "
2080Sstevel@tonic-gate 	    "have been detected in more than one set.\n"
2090Sstevel@tonic-gate 	    "Import recommendation based upon set creation time.\n"
2100Sstevel@tonic-gate 	    "Proceed with the import with caution."));
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/*
2130Sstevel@tonic-gate 	 * Look at all overlapping disks. Determine which slice
2140Sstevel@tonic-gate 	 * would have a replica on it. i.e. either slice 7 or 6.
2150Sstevel@tonic-gate 	 * Then read the master block. If the disk doesn't have a
2160Sstevel@tonic-gate 	 * metadb on it, the master block is a dummy master block.
2170Sstevel@tonic-gate 	 * Both dummy or normal master block contain the timestamp
2180Sstevel@tonic-gate 	 * which is what we are after. Use this timestamp to issue
2190Sstevel@tonic-gate 	 * the appropriate recommendation.
2200Sstevel@tonic-gate 	 */
2210Sstevel@tonic-gate 	mbp = Malloc(DEV_BSIZE);
2220Sstevel@tonic-gate 	for (d = overlap_disks; d != NULL; d = d->overlap) {
2230Sstevel@tonic-gate 		mdname_t	*rsp;
2240Sstevel@tonic-gate 		uint_t		sliceno;
2250Sstevel@tonic-gate 		int		fd = -1;
2260Sstevel@tonic-gate 
2271945Sjeanm 		/*
2281945Sjeanm 		 * If the disk isn't available (i.e. powered off or dead)
2291945Sjeanm 		 * we can't read the master block timestamp and thus
2301945Sjeanm 		 * cannot make a recommendation as to which set it belongs to.
2311945Sjeanm 		 */
2321945Sjeanm 		if (d->mid_available != MD_IM_DISK_AVAILABLE) {
2331945Sjeanm 			(void) fprintf(stdout, "  %s ", d->mid_dnp->cname);
2341945Sjeanm 			(void) fprintf(stdout,
2351945Sjeanm 			    gettext(" - no recommendation can "
2361945Sjeanm 			    "be made because disk is unavailable\n"));
2371945Sjeanm 			continue;
2381945Sjeanm 		}
2391945Sjeanm 
2400Sstevel@tonic-gate 		if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0)
2410Sstevel@tonic-gate 			continue;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 		if (d->mid_dnp->vtoc.parts[sliceno].size == 0)
2440Sstevel@tonic-gate 			continue;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		if ((rsp = metaslicename(d->mid_dnp, sliceno, ep)) == NULL)
2470Sstevel@tonic-gate 			continue;
2480Sstevel@tonic-gate 		if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0)
2490Sstevel@tonic-gate 			continue;
2500Sstevel@tonic-gate 		if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) {
2510Sstevel@tonic-gate 			(void) close(fd);
2520Sstevel@tonic-gate 			mdclrerror(ep);
2530Sstevel@tonic-gate 			continue;
2540Sstevel@tonic-gate 		}
2550Sstevel@tonic-gate 		(void) close(fd);
256*11053SSurya.Prakki@Sun.COM 		(void) fprintf(stdout, "  %s ", d->mid_dnp->cname);
257*11053SSurya.Prakki@Sun.COM 		(void) fprintf(stdout, "%s: %s\n",
2581945Sjeanm 		    gettext(" - must import with set "
2590Sstevel@tonic-gate 		    "created at "), meta_print_time((md_timeval32_t *)
2600Sstevel@tonic-gate 		    (&(mbp->mb_setcreatetime))));
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 	Free(mbp);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2651945Sjeanm /*
2661945Sjeanm  * is_first_disk is called to determine if the disk passed to it is
2671945Sjeanm  * eligible to be used as the "first disk time" in the set. It checks to
2681945Sjeanm  * see if the disk is available, on the skip list or not (thus already in
2691945Sjeanm  * an importable set) or being used by the system already.
2701945Sjeanm  * RETURN:
2711945Sjeanm  *	1	The time can be used as the first disk time
2721945Sjeanm  *	0	The time should not be used.
2731945Sjeanm  */
2741945Sjeanm static int
is_first_disk(md_im_drive_info_t * d,mddrivenamelist_t ** skiph)2751945Sjeanm is_first_disk(
2761945Sjeanm md_im_drive_info_t	*d,
2771945Sjeanm mddrivenamelist_t	**skiph)
2781945Sjeanm {
2791945Sjeanm 	mddrivenamelist_t	*slp;
2801945Sjeanm 	md_error_t		status = mdnullerror;
2811945Sjeanm 	md_error_t		*ep = &status;
2821945Sjeanm 	mdsetname_t		*sp = metasetname(MD_LOCAL_NAME, ep);
2831945Sjeanm 
2841945Sjeanm 	/*
2851945Sjeanm 	 * If a disk is not available there is no
2861945Sjeanm 	 * set creation timestamp available.
2871945Sjeanm 	 */
2881945Sjeanm 	if (d->mid_available == MD_IM_DISK_AVAILABLE) {
2891945Sjeanm 		/*
2901945Sjeanm 		 * We also need to make sure this disk isn't already on
2911945Sjeanm 		 * the skip list.
2921945Sjeanm 		 */
2931945Sjeanm 		for (slp = *skiph; slp != NULL; slp = slp->next) {
2941945Sjeanm 			if (d->mid_dnp == slp->drivenamep)
2951945Sjeanm 				return (0);
2961945Sjeanm 		}
2971945Sjeanm 		/*
2981945Sjeanm 		 * And we need to make sure the drive isn't
2991945Sjeanm 		 * currently being used for something else
3001945Sjeanm 		 * like a mounted file system or a current
3011945Sjeanm 		 * metadevice or in a set.
3021945Sjeanm 		 */
3031945Sjeanm 		if (meta_imp_drvused(sp, d->mid_dnp, ep)) {
3041945Sjeanm 			return (0);
3051945Sjeanm 		}
3061945Sjeanm 	} else {
3071945Sjeanm 		return (0);
3081945Sjeanm 	}
3091945Sjeanm 	return (1);
3101945Sjeanm }
3111945Sjeanm 
3121945Sjeanm /*
3131945Sjeanm  * Input a list of disks (dnlp), find the sets that are importable, create
3141945Sjeanm  * a list of these sets (mispp), and a list of the disks within each of these
3151945Sjeanm  * sets (midp). These lists (mispp and midp) will be used by metaimport.
3161945Sjeanm  */
process_disks(mddrivenamelist_t * dnlp,mddrivenamelist_t ** skipt,md_im_set_desc_t ** mispp,int flags,int * set_count,int overlap,md_error_t * ep)3171945Sjeanm static int process_disks(
3181945Sjeanm 	mddrivenamelist_t	*dnlp,
3191945Sjeanm 	mddrivenamelist_t	**skipt,
3201945Sjeanm 	md_im_set_desc_t	**mispp,
3211945Sjeanm 	int			flags,
3221945Sjeanm 	int			*set_count,
3231945Sjeanm 	int			overlap,
3241945Sjeanm 	md_error_t		*ep
3251945Sjeanm )
3261945Sjeanm {
3271945Sjeanm 	mddrivenamelist_t	*dp;
3281945Sjeanm 	int			rscount = 0;
3291945Sjeanm 	int			hasreplica;
3301945Sjeanm 	md_im_set_desc_t	*p;
3311945Sjeanm 	md_im_drive_info_t	*d;
3321945Sjeanm 	mddrivenamelist_t	**skiph = skipt;
3331945Sjeanm 
3341945Sjeanm 	/* Scan qualified disks */
3351945Sjeanm 	for (dp = dnlp; dp != NULL; dp = dp->next) {
3361945Sjeanm 		mddrivenamelist_t *slp;
3371945Sjeanm 
3381945Sjeanm 		/* is the current drive on the skip list? */
3391945Sjeanm 		for (slp = *skiph; slp != NULL; slp = slp->next) {
340*11053SSurya.Prakki@Sun.COM 			if (dp->drivenamep == slp->drivenamep)
341*11053SSurya.Prakki@Sun.COM 				break;
3421945Sjeanm 		}
3431945Sjeanm 		/* drive on the skip list ? */
3441945Sjeanm 		if (slp != NULL)
3451945Sjeanm 			continue;
3461945Sjeanm 
3471945Sjeanm 		/*
3481945Sjeanm 		 * In addition to updating the misp list, either verbose or
3491945Sjeanm 		 * standard output will be generated.
3501945Sjeanm 		 *
3511945Sjeanm 		 */
3521945Sjeanm 		hasreplica = meta_get_and_report_set_info(dp, mispp, 0,
3531945Sjeanm 		    flags, set_count, overlap, overlap_disks, ep);
3541945Sjeanm 
3551945Sjeanm 		if (hasreplica < 0) {
3561945Sjeanm 			mde_perror(ep, "");
3571945Sjeanm 			mdclrerror(ep);
3581945Sjeanm 		} else {
3591945Sjeanm 
3601945Sjeanm 			rscount += hasreplica;
3611945Sjeanm 
3621945Sjeanm 			/* Eliminate duplicate reporting */
3631945Sjeanm 			if (hasreplica > 0) {
3641945Sjeanm 				md_timeval32_t	firstdisktime;
3651945Sjeanm 
3661945Sjeanm 				/*
3671945Sjeanm 				 * Go to the tail for the current set
3681945Sjeanm 				 */
3691945Sjeanm 				for (p = *mispp; p->mis_next != NULL;
370*11053SSurya.Prakki@Sun.COM 				    p = p->mis_next)
371*11053SSurya.Prakki@Sun.COM 				;
3721945Sjeanm 
3731945Sjeanm 				/*
3741945Sjeanm 				 * Now look for the set creation timestamp.
3751945Sjeanm 				 * If a disk is not available there is no
3761945Sjeanm 				 * set creation timestamp available so look
3771945Sjeanm 				 * for the first available disk to grab this
3781945Sjeanm 				 * information from. We also need to make
3791945Sjeanm 				 * sure this disk isn't already on the skip
3801945Sjeanm 				 * list. If so go to the next available drive.
3811945Sjeanm 				 * And we need to make sure the drive isn't
3821945Sjeanm 				 * currently being used for something else
3831945Sjeanm 				 * like a mounted file system or a current
3841945Sjeanm 				 * metadevice or in a set.
3851945Sjeanm 				 */
3861945Sjeanm 				for (d = p->mis_drives; d != NULL;
3871945Sjeanm 				    d = d->mid_next) {
3881945Sjeanm 					if (is_first_disk(d, skiph)) {
3891945Sjeanm 						firstdisktime =
3901945Sjeanm 						    d->mid_setcreatetimestamp;
3911945Sjeanm 						break;
3921945Sjeanm 					}
3931945Sjeanm 				}
3941945Sjeanm 				for (d = p->mis_drives; d != NULL;
3951945Sjeanm 				    d = d->mid_next) {
3961945Sjeanm 					/*
3971945Sjeanm 					 * if the mb_setcreatetime for a disk
3981945Sjeanm 					 * is not the same as the first disk
3991945Sjeanm 					 * in the set, don't put it on the
4001945Sjeanm 					 * skip list. This disk probably
4011945Sjeanm 					 * doesn't really belong in this set
4021945Sjeanm 					 * and we'll want to look at it again
4031945Sjeanm 					 * to figure out where it does belong.
4041945Sjeanm 					 * If the disk isn't available, there's
4051945Sjeanm 					 * really no point in looking at it
4061945Sjeanm 					 * again so put it on the skip list.
4071945Sjeanm 					 */
4081945Sjeanm 					if (d->mid_available ==
4091945Sjeanm 					    MD_IM_DISK_AVAILABLE) {
4101945Sjeanm 						if ((d->mid_setcreatetimestamp.
4111945Sjeanm 						    tv_sec != firstdisktime.
4121945Sjeanm 						    tv_sec) ||
4131945Sjeanm 						    (d->mid_setcreatetimestamp.
4141945Sjeanm 						    tv_usec !=
4151945Sjeanm 						    firstdisktime.tv_usec))
4161945Sjeanm 							continue;
4171945Sjeanm 					}
4181945Sjeanm 					skipt =
4191945Sjeanm 					    meta_drivenamelist_append_wrapper(
420*11053SSurya.Prakki@Sun.COM 					    skipt, d->mid_dnp);
4211945Sjeanm 				}
4221945Sjeanm 			}
4231945Sjeanm 		}
4241945Sjeanm 	}
4251945Sjeanm 	return (rscount);
4261945Sjeanm }
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate int
main(int argc,char * argv[])4290Sstevel@tonic-gate main(int argc, char *argv[])
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	char			c;
4320Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
4330Sstevel@tonic-gate 	md_error_t		*ep = &status;
4340Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
4350Sstevel@tonic-gate 	char			*setname_new = NULL;
4360Sstevel@tonic-gate 	int			report_only = 0;
4370Sstevel@tonic-gate 	int			version = 0;
4380Sstevel@tonic-gate 	bool_t			dry_run = 0;
4390Sstevel@tonic-gate 	md_im_names_t		cnames = { 0, NULL };
4400Sstevel@tonic-gate 	int			err_on_prune = 0;
4410Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
4420Sstevel@tonic-gate 	mddrivenamelist_t	*dp;
4430Sstevel@tonic-gate 	mddrivenamelist_t	*skiph = NULL;
4440Sstevel@tonic-gate 	int			rscount = 0;
4451945Sjeanm 	md_im_set_desc_t	*pass1_misp = NULL;
4460Sstevel@tonic-gate 	md_im_set_desc_t	*misp = NULL;
4471945Sjeanm 	md_im_set_desc_t	**pass1_mispp = &pass1_misp;
4480Sstevel@tonic-gate 	md_im_set_desc_t	**mispp = &misp;
4490Sstevel@tonic-gate 	mhd_mhiargs_t		mhiargs = defmhiargs;
4500Sstevel@tonic-gate 	int			have_multiple_sets = 0;
4510Sstevel@tonic-gate 	int			force = 0;
4520Sstevel@tonic-gate 	int			overlap = 0;
453734Smw145384 	uint_t			imp_flags = 0;
454734Smw145384 	int			set_count = 0;
4551945Sjeanm 	int			no_quorum = 0;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/*
4580Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
4590Sstevel@tonic-gate 	 * with messages to output.  Just in case we're not in a build
4600Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
4610Sstevel@tonic-gate 	 * something.
4620Sstevel@tonic-gate 	 */
4630Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
4640Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
4650Sstevel@tonic-gate #endif
4660Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4670Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/*
4700Sstevel@tonic-gate 	 * Check to see if the libsds_sc.so is bound on the
4710Sstevel@tonic-gate 	 * current system. If it is, it means the system is
4720Sstevel@tonic-gate 	 * part of a cluster.
4730Sstevel@tonic-gate 	 *
4740Sstevel@tonic-gate 	 * The import operation is currently not supported
4750Sstevel@tonic-gate 	 * in a SunCluster environment.
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	if (sdssc_bind_library() != SDSSC_NOT_BOUND) {
478*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext(
4790Sstevel@tonic-gate 		    "%s: Import operation not supported under SunCluster\n"),
4800Sstevel@tonic-gate 		    argv[0]);
4810Sstevel@tonic-gate 		exit(0);
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/* initialize */
4850Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
4860Sstevel@tonic-gate 		mde_perror(ep, "");
4870Sstevel@tonic-gate 		md_exit(sp, 1);
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	optind = 1;
4910Sstevel@tonic-gate 	opterr = 1;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "frns:vV?")) != -1) {
4940Sstevel@tonic-gate 		switch (c) {
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		case 'f':
4970Sstevel@tonic-gate 			force = 1;
4980Sstevel@tonic-gate 			break;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 		case 'n':
5010Sstevel@tonic-gate 			dry_run = 1;
5020Sstevel@tonic-gate 			break;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		case 'r':
5050Sstevel@tonic-gate 			report_only = 1;
506734Smw145384 			imp_flags |= META_IMP_REPORT;
5070Sstevel@tonic-gate 			break;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		case 's':
5100Sstevel@tonic-gate 			setname_new = optarg;
5110Sstevel@tonic-gate 			break;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		case 'v':
514734Smw145384 			imp_flags |= META_IMP_VERBOSE;
5150Sstevel@tonic-gate 			break;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		case 'V':
5180Sstevel@tonic-gate 			version = 1;
5190Sstevel@tonic-gate 			break;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 		case '?':
5220Sstevel@tonic-gate 		default:
5230Sstevel@tonic-gate 			usage(sp, NULL);
5240Sstevel@tonic-gate 			break;
5250Sstevel@tonic-gate 		}
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	if (version == 1)
5290Sstevel@tonic-gate 		print_version(sp);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	/* Detect conflicting options */
5320Sstevel@tonic-gate 	if ((dry_run != 0) && (report_only != 0))
5330Sstevel@tonic-gate 		usage(sp, gettext("The -n and -r options conflict."));
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if ((report_only != 0) && (setname_new != NULL))
5360Sstevel@tonic-gate 		usage(sp, gettext("The -r and -s options conflict."));
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	if ((report_only == 0) && (setname_new == NULL))
5390Sstevel@tonic-gate 		usage(sp, gettext("You must specify either -r or -s."));
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	/* Don't do any real work if we don't have root privilege */
5420Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
5430Sstevel@tonic-gate 		mde_perror(ep, "");
5440Sstevel@tonic-gate 		md_exit(sp, 1);
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
5480Sstevel@tonic-gate 		mde_perror(ep, "");
5490Sstevel@tonic-gate 		if (mdismddberror(ep, MDE_DB_STALE))
5500Sstevel@tonic-gate 			md_exit(sp, 66);
5510Sstevel@tonic-gate 		if (! mdiserror(ep, MDE_MDDB_CKSUM))
5520Sstevel@tonic-gate 			md_exit(sp, 1);
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/*
5560Sstevel@tonic-gate 	 * Read remaining arguments into drive name list, otherwise
5570Sstevel@tonic-gate 	 * call routine to list all drives in system.
5580Sstevel@tonic-gate 	 */
5590Sstevel@tonic-gate 	if (argc > optind) {
5600Sstevel@tonic-gate 		int i;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 		/* For user specified disks, they MUST not be in use */
5630Sstevel@tonic-gate 		err_on_prune = 1;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 		/* All remaining args should be disks */
5660Sstevel@tonic-gate 		cnames.min_count = argc - optind;
5670Sstevel@tonic-gate 		cnames.min_names = Malloc(cnames.min_count * sizeof (char *));
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 		for (i = 0; i < cnames.min_count; i++, optind++) {
5700Sstevel@tonic-gate 			mddrivename_t *dnp;
5710Sstevel@tonic-gate 			dnp = metadrivename(&sp, argv[optind], ep);
5720Sstevel@tonic-gate 			if (dnp == NULL) {
5730Sstevel@tonic-gate 				mde_perror(ep, "");
5740Sstevel@tonic-gate 				md_exit(sp, 1);
5750Sstevel@tonic-gate 			} else {
5760Sstevel@tonic-gate 				cnames.min_names[i] = dnp->rname;
5770Sstevel@tonic-gate 			}
5780Sstevel@tonic-gate 		}
5790Sstevel@tonic-gate 	} else {
5800Sstevel@tonic-gate 		if (meta_list_disks(ep, &cnames) != 0) {
5810Sstevel@tonic-gate 			mde_perror(ep, "");
5820Sstevel@tonic-gate 			md_exit(sp, 1);
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/*
5870Sstevel@tonic-gate 	 * If the user specified disks on the command line, min_count will be
5880Sstevel@tonic-gate 	 * greater than zero.  If they didn't, it should be safe to assume that
5890Sstevel@tonic-gate 	 * the system in question has at least one drive detected by the
5900Sstevel@tonic-gate 	 * snapshot code, or we would have barfed earlier initializing the
5910Sstevel@tonic-gate 	 * metadb.
5920Sstevel@tonic-gate 	 */
5930Sstevel@tonic-gate 	assert(cnames.min_count > 0);
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	/*
5960Sstevel@tonic-gate 	 * Prune the list:
5970Sstevel@tonic-gate 	 * - get rid of drives in current svm configuration
5980Sstevel@tonic-gate 	 * - get rid of mounted drives
5990Sstevel@tonic-gate 	 * - get rid of swap drives
6000Sstevel@tonic-gate 	 * - get rid of drives in other sets
6010Sstevel@tonic-gate 	 *
6020Sstevel@tonic-gate 	 * If drives were specified on the command line, it should be
6030Sstevel@tonic-gate 	 * an error to find in-use disks in the list.  (err_on_prune)
6040Sstevel@tonic-gate 	 *
6050Sstevel@tonic-gate 	 * On return from meta_prune_cnames call, dnlp
6060Sstevel@tonic-gate 	 * will have candidate for replica scan.
6070Sstevel@tonic-gate 	 */
6080Sstevel@tonic-gate 	dnlp = meta_prune_cnames(ep, &cnames, err_on_prune);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	/*
6110Sstevel@tonic-gate 	 * Doctor the drive string in the error structure to list all of the
6120Sstevel@tonic-gate 	 * unused disks, rather than just one.  The output will be done in the
6130Sstevel@tonic-gate 	 * following !mdisok() block.
6140Sstevel@tonic-gate 	 */
6150Sstevel@tonic-gate 	if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) {
6160Sstevel@tonic-gate 		md_ds_error_t		*ip =
6170Sstevel@tonic-gate 		    &ep->info.md_error_info_t_u.ds_error;
6180Sstevel@tonic-gate 		char			*dlist;
6190Sstevel@tonic-gate 		int			sizecnt = 0;
6200Sstevel@tonic-gate 
6211945Sjeanm 		/* add 1 for null terminator */
6221945Sjeanm 		sizecnt += strlen(ip->drive) + 1;
6230Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
6240Sstevel@tonic-gate 			sizecnt += 2; /* for the ", " */
6250Sstevel@tonic-gate 			sizecnt += strlen(dp->drivenamep->cname);
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		dlist = Malloc(sizecnt);
6290Sstevel@tonic-gate 
630*11053SSurya.Prakki@Sun.COM 		(void) strlcpy(dlist, ip->drive, sizecnt);
6311945Sjeanm 
6320Sstevel@tonic-gate 		Free(ip->drive);
6330Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
634*11053SSurya.Prakki@Sun.COM 			(void) strlcat(dlist, ", ", sizecnt);
635*11053SSurya.Prakki@Sun.COM 			(void) strlcat(dlist, dp->drivenamep->cname, sizecnt);
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 
6381945Sjeanm 		ip->drive = dlist;
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/* Don't continue if we're already hosed */
6420Sstevel@tonic-gate 	if (!mdisok(ep)) {
6430Sstevel@tonic-gate 		mde_perror(ep, "");
6440Sstevel@tonic-gate 		md_exit(sp, 1);
6450Sstevel@tonic-gate 	}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	/* ...or if there's nothing to scan */
6480Sstevel@tonic-gate 	if (dnlp == NULL) {
6490Sstevel@tonic-gate 		md_eprintf("%s\n", gettext("no unused disks detected"));
6500Sstevel@tonic-gate 		md_exit(sp, 0);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6531945Sjeanm 	/*
6541945Sjeanm 	 * META_IMP_PASS1 means gather the info, but don't report.
6551945Sjeanm 	 */
6561945Sjeanm 	(void) process_disks(dnlp, &skiph, pass1_mispp,
6571945Sjeanm 	    imp_flags | META_IMP_PASS1, &set_count, overlap, ep);
6580Sstevel@tonic-gate 
6591945Sjeanm 	overlap_disks = NULL;
6601945Sjeanm 	overlap = set_disk_overlap(pass1_misp);
6611945Sjeanm 	skiph = NULL;
6620Sstevel@tonic-gate 
6631945Sjeanm 	/*
6641945Sjeanm 	 * This time call without META_IMP_PASS1 set and we gather
6651945Sjeanm 	 * and report the information.
6661945Sjeanm 	 * We need to do this twice because of the overlap detection.
6671945Sjeanm 	 * The first pass generates a list of disks to detect overlap on.
6681945Sjeanm 	 * We then do a second pass using that overlap list to generate
6691945Sjeanm 	 * the report.
6701945Sjeanm 	 */
6711945Sjeanm 	rscount = process_disks(dnlp, &skiph, mispp, imp_flags, &set_count,
6721945Sjeanm 	    overlap, ep);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/*
6750Sstevel@tonic-gate 	 * Now have entire list of disks associated with diskset including
6760Sstevel@tonic-gate 	 * disks listed in mddb locator blocks and namespace. Before importing
6770Sstevel@tonic-gate 	 * diskset need to recheck that none of these disks is already in use.
6780Sstevel@tonic-gate 	 * If a disk is found that is already in use, print error and exit.
6790Sstevel@tonic-gate 	 */
6800Sstevel@tonic-gate 	if (!report_only) {
6810Sstevel@tonic-gate 		md_im_set_desc_t	*p;
6820Sstevel@tonic-gate 		md_im_drive_info_t	*d;
6830Sstevel@tonic-gate 		mddrivename_t		*dnp;
6840Sstevel@tonic-gate 
6851945Sjeanm 		if (sp == NULL) {
6861945Sjeanm 			/* Get sp for local set */
6871945Sjeanm 			if ((sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
6881945Sjeanm 				mde_perror(ep, "");
6891945Sjeanm 				meta_free_im_set_desc(misp);
6901945Sjeanm 				md_exit(sp, 1);
6911945Sjeanm 			}
6921945Sjeanm 		}
6931945Sjeanm 
6940Sstevel@tonic-gate 		for (p = misp; p != NULL; p = p->mis_next) {
6950Sstevel@tonic-gate 			for (d = p->mis_drives; d != NULL; d = d->mid_next) {
6960Sstevel@tonic-gate 				dnp = d->mid_dnp;
6971945Sjeanm 				if (d->mid_available == MD_IM_DISK_AVAILABLE) {
6981945Sjeanm 					if (meta_imp_drvused(sp, dnp, ep)) {
6991945Sjeanm 						(void) mddserror(ep,
7001945Sjeanm 						    MDE_DS_DRIVEINUSE, 0, NULL,
7011945Sjeanm 						    dnp->cname, NULL);
7021945Sjeanm 						mde_perror(ep, "");
7031945Sjeanm 						meta_free_im_set_desc(misp);
7041945Sjeanm 						md_exit(sp, 1);
7051945Sjeanm 					}
7061945Sjeanm 				} else {
7071945Sjeanm 					/*
7081945Sjeanm 					 * If drive is unavailable, then check
7091945Sjeanm 					 * that this drive hasn't already been
7101945Sjeanm 					 * imported as part of another partial
7111945Sjeanm 					 * diskset.  Check by devid instead of
7121945Sjeanm 					 * cname since the unavailable drive
7131945Sjeanm 					 * would have the cname from its
7141945Sjeanm 					 * previous system and this may collide
7151945Sjeanm 					 * with a valid cname on this system.
7161945Sjeanm 					 * Fail if devid is found in another
7171945Sjeanm 					 * set or if the routine fails.
7181945Sjeanm 					 */
7191945Sjeanm 					mdsetname_t	*tmp_sp = NULL;
7201945Sjeanm 
7211945Sjeanm 					if ((meta_is_devid_in_anyset(
7221945Sjeanm 					    d->mid_devid, &tmp_sp, ep) == -1) ||
7231945Sjeanm 					    (tmp_sp != NULL)) {
7241945Sjeanm 						(void) mddserror(ep,
7251945Sjeanm 						    MDE_DS_DRIVEINUSE, 0, NULL,
7261945Sjeanm 						    dnp->cname, NULL);
7271945Sjeanm 						mde_perror(ep, "");
7281945Sjeanm 						meta_free_im_set_desc(misp);
7291945Sjeanm 						md_exit(sp, 1);
7301945Sjeanm 					}
7310Sstevel@tonic-gate 				}
7320Sstevel@tonic-gate 			}
7330Sstevel@tonic-gate 		}
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/*
7370Sstevel@tonic-gate 	 * If there are no unconfigured sets, then our work here is done.
7380Sstevel@tonic-gate 	 * Hopefully this is friendlier than just not printing anything at all.
7390Sstevel@tonic-gate 	 */
7400Sstevel@tonic-gate 	if (rscount == 0) {
74157Sjeanm 		/*
74257Sjeanm 		 * If we've found partial disksets but no complete disksets,
74357Sjeanm 		 * we don't want this to print.
74457Sjeanm 		 */
7451945Sjeanm 		if (!misp) {
74657Sjeanm 			md_eprintf("%s\n", gettext("no unconfigured sets "
74757Sjeanm 			    "detected"));
7481945Sjeanm 			meta_free_im_set_desc(misp);
7491945Sjeanm 			md_exit(sp, 1);
75057Sjeanm 		}
7510Sstevel@tonic-gate 		md_exit(sp, 0);
7520Sstevel@tonic-gate 	}
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	/*
7550Sstevel@tonic-gate 	 * We'll need this info for both the report content and the import
7560Sstevel@tonic-gate 	 * decision.  By the time we're here, misp should NOT be NULL (or we
7570Sstevel@tonic-gate 	 * would have exited in the rscount == 0 test above).
7580Sstevel@tonic-gate 	 */
7590Sstevel@tonic-gate 	assert(misp != NULL);
7600Sstevel@tonic-gate 	if (misp->mis_next != NULL) {
7610Sstevel@tonic-gate 		have_multiple_sets = 1;
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate 	/*
7640Sstevel@tonic-gate 	 * Generate the appropriate (verbose or not) report for all sets
7650Sstevel@tonic-gate 	 * detected.  If we're planning on importing later, only include the
7660Sstevel@tonic-gate 	 * "suggested import" command if multiple sets were detected.  (That
7670Sstevel@tonic-gate 	 * way, when we error out later, we have still provided useful
7680Sstevel@tonic-gate 	 * information.)
7690Sstevel@tonic-gate 	 */
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/*
7720Sstevel@tonic-gate 	 * Now we should have all the unconfigured sets detected
7730Sstevel@tonic-gate 	 * check for the overlapping
7740Sstevel@tonic-gate 	 */
7750Sstevel@tonic-gate 	if (have_multiple_sets) {
776734Smw145384 		/* Printing out how many candidate disksets we found. */
777734Smw145384 		if (imp_flags & META_IMP_REPORT) {
778734Smw145384 			(void) printf("%s: %i\n\n",
779734Smw145384 			    gettext("Number of disksets eligible for import"),
780734Smw145384 			    set_count);
781734Smw145384 		}
7821945Sjeanm 	}
7831945Sjeanm 	if (overlap) {
7841945Sjeanm 		report_overlap_recommendation();
7851945Sjeanm 	}
786734Smw145384 
7871945Sjeanm 	if (have_multiple_sets && !report_only) {
7881945Sjeanm 		md_eprintf("%s\n\n", gettext("multiple unconfigured "
7891945Sjeanm 		    "sets detected.\nRerun the command with the "
7901945Sjeanm 		    "suggested options for the desired set."));
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	/*
7950Sstevel@tonic-gate 	 * If it's a report-only request, we're done.  If it's an import
7960Sstevel@tonic-gate 	 * request, make sure that we only have one entry in the set list.
7970Sstevel@tonic-gate 	 */
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	if (report_only) {
8001945Sjeanm 		meta_free_im_set_desc(misp);
8010Sstevel@tonic-gate 		md_exit(sp, 0);
8020Sstevel@tonic-gate 	} else if (have_multiple_sets) {
8031945Sjeanm 		meta_free_im_set_desc(misp);
8041945Sjeanm 		md_exit(sp, 1);
8051945Sjeanm 	} else if (overlap) {
8061945Sjeanm 		md_im_drive_info_t	*d;
8071945Sjeanm 		/*
8081945Sjeanm 		 * The only way we can get here is if we're doing an import
8091945Sjeanm 		 * request on a set that contains at least one disk with
8101945Sjeanm 		 * a time conflict. We are prohibiting the importation of
8111945Sjeanm 		 * this type of set until the offending disk(s) are turned
8121945Sjeanm 		 * off to prevent data corruption.
8131945Sjeanm 		 */
814*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("To import this set, "));
8151945Sjeanm 		for (d = pass1_misp->mis_drives;
8161945Sjeanm 		    d != NULL;
8171945Sjeanm 		    d = d->mid_next) {
8181945Sjeanm 			if (d->overlapped_disk)
819*11053SSurya.Prakki@Sun.COM 				(void) printf("%s ", d->mid_dnp->cname);
8201945Sjeanm 		}
821*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("must be removed from the system\n"));
8221945Sjeanm 		meta_free_im_set_desc(misp);
8230Sstevel@tonic-gate 		md_exit(sp, 1);
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	if (setname_new == NULL) {
8270Sstevel@tonic-gate 		usage(sp, gettext("You must specify a new set name."));
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8301945Sjeanm 	/*
8311945Sjeanm 	 * The user must specify the -f (force) flag if the following
8321945Sjeanm 	 * conditions exist:
8331945Sjeanm 	 *		- partial diskset
8341945Sjeanm 	 *		- stale diskset
8351945Sjeanm 	 */
8361945Sjeanm 	if (meta_replica_quorum(misp) != 0)
8371945Sjeanm 		no_quorum = 1;
8381945Sjeanm 	if (misp->mis_partial || no_quorum) {
8391945Sjeanm 		if (!force)
8401945Sjeanm 			usage(sp, gettext("You must specify the force flag"));
8411945Sjeanm 	}
8420Sstevel@tonic-gate 	(void) meta_imp_set(misp, setname_new, force, dry_run, ep);
8430Sstevel@tonic-gate 	if (dry_run) {
8441945Sjeanm 		meta_free_im_set_desc(misp);
8450Sstevel@tonic-gate 		md_exit(sp, 0);
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	if (!mdisok(ep)) {
8491945Sjeanm 		meta_free_im_set_desc(misp);
8500Sstevel@tonic-gate 		mde_perror(ep, "");
8510Sstevel@tonic-gate 		md_exit(sp, 1);
8520Sstevel@tonic-gate 	}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	if ((sp = metasetname(setname_new, ep)) == NULL) {
8551945Sjeanm 		meta_free_im_set_desc(misp);
8560Sstevel@tonic-gate 		mde_perror(ep, "");
8570Sstevel@tonic-gate 		md_exit(sp, 1);
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
8611945Sjeanm 		meta_free_im_set_desc(misp);
8620Sstevel@tonic-gate 		mde_perror(ep, "");
8630Sstevel@tonic-gate 		md_exit(sp, 10);	/* special errcode */
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 
8661945Sjeanm 	if (meta_set_take(sp, &mhiargs, (misp->mis_partial | TAKE_IMP),
8671945Sjeanm 	    0, &status)) {
8681945Sjeanm 		meta_free_im_set_desc(misp);
8690Sstevel@tonic-gate 		mde_perror(&status, "");
8700Sstevel@tonic-gate 		md_exit(sp, 1);
8710Sstevel@tonic-gate 	}
8720Sstevel@tonic-gate 
8731945Sjeanm 	meta_free_im_set_desc(misp);
8740Sstevel@tonic-gate 	md_exit(sp, 0);
8750Sstevel@tonic-gate 	/*NOTREACHED*/
8760Sstevel@tonic-gate 	return (0);
8770Sstevel@tonic-gate }
878