10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1945Sjeanm  * Common Development and Distribution License (the "License").
6*1945Sjeanm  * 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*1945Sjeanm  * 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  * Utility to import SVM disksets into an active SVM configuration.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <assert.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <meta.h>
360Sstevel@tonic-gate #include <sys/utsname.h>
370Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
380Sstevel@tonic-gate #include <sys/lvm/md_names.h>
390Sstevel@tonic-gate #include <sdssc.h>
400Sstevel@tonic-gate 
41*1945Sjeanm static md_im_drive_info_t	*overlap_disks;
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static void
440Sstevel@tonic-gate usage(mdsetname_t *sp, char *string)
450Sstevel@tonic-gate {
460Sstevel@tonic-gate 	if ((string != NULL) && (*string != '\0'))
470Sstevel@tonic-gate 		md_eprintf("%s\n", string);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 	(void) fprintf(stderr,
500Sstevel@tonic-gate 	    "%s:\t%s -s setname [-n] [-f] [-v] [%s...]\n",
510Sstevel@tonic-gate 	    gettext("usage"), myname, gettext("disk"));
520Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -r [%s...]\n",
530Sstevel@tonic-gate 	    myname, gettext("disk"));
540Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -?\n", myname);
550Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -V\n", myname);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 	md_exit(sp, (string == NULL) ? 0 : 1);
580Sstevel@tonic-gate }
590Sstevel@tonic-gate 
600Sstevel@tonic-gate static void
610Sstevel@tonic-gate print_version(mdsetname_t *sp)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	struct utsname curname;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	if (uname(&curname) == -1) {
660Sstevel@tonic-gate 		md_eprintf("%s\n", strerror(errno));
670Sstevel@tonic-gate 		md_exit(sp, 1);
680Sstevel@tonic-gate 	}
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	(void) fprintf(stderr, "%s %s\n", myname, curname.version);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	md_exit(sp, 0);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * Returns 0 if there is no overlap, 1 otherwise
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate static int
790Sstevel@tonic-gate set_disk_overlap(md_im_set_desc_t *misp)
800Sstevel@tonic-gate {
81*1945Sjeanm 	md_im_set_desc_t	*next, *isp = misp;
82*1945Sjeanm 	md_im_drive_info_t	*set_dr, *next_set_dr, **chain;
83*1945Sjeanm 	int			is_overlap = 0;
84*1945Sjeanm 	md_im_drive_info_t	*good_disk = NULL;
85*1945Sjeanm 	md_im_drive_info_t	*d;
86*1945Sjeanm 	md_timeval32_t		gooddisktime;
87*1945Sjeanm 	int			disk_not_available = 0;
88*1945Sjeanm 	/*
89*1945Sjeanm 	 * There are 2 ways we could get an "overlap" disk.
90*1945Sjeanm 	 * One is if the ctd's are the same. The other is if
91*1945Sjeanm 	 * the setcreatetimestamp on the disk doesn't agree with the
92*1945Sjeanm 	 * "good" disk in the set. However, if we have a disk that is
93*1945Sjeanm 	 * unavailable and the other instance of the ctd is available we
94*1945Sjeanm 	 * really don't have a conflict. It's just that the unavailable ctd
95*1945Sjeanm 	 * is it's "old" location and the available instance is a current
96*1945Sjeanm 	 * location.
97*1945Sjeanm 	 */
980Sstevel@tonic-gate 	for (; isp != NULL; isp = isp->mis_next) {
990Sstevel@tonic-gate 	    for (next = isp->mis_next; next != NULL; next = next->mis_next) {
1000Sstevel@tonic-gate 		for (set_dr = isp->mis_drives; set_dr != NULL;
101*1945Sjeanm 		    set_dr = set_dr->mid_next) {
102*1945Sjeanm 		    if (set_dr->mid_available == MD_IM_DISK_NOT_AVAILABLE)
103*1945Sjeanm 			disk_not_available = 1;
104*1945Sjeanm 		    else
105*1945Sjeanm 			disk_not_available = 0;
106*1945Sjeanm 		    for (next_set_dr = next->mis_drives; next_set_dr != NULL;
107*1945Sjeanm 			next_set_dr = next_set_dr->mid_next) {
108*1945Sjeanm 			if (disk_not_available &&
109*1945Sjeanm 			    (next_set_dr->mid_available
110*1945Sjeanm 			    == MD_IM_DISK_AVAILABLE))
111*1945Sjeanm 				continue;
112*1945Sjeanm 			else if (!disk_not_available &&
113*1945Sjeanm 			    (next_set_dr->mid_available ==
114*1945Sjeanm 			    MD_IM_DISK_NOT_AVAILABLE))
115*1945Sjeanm 				continue;
116*1945Sjeanm 			if (strcmp(set_dr->mid_dnp->cname,
117*1945Sjeanm 			    next_set_dr->mid_dnp->cname) == 0) {
1180Sstevel@tonic-gate 				/*
119*1945Sjeanm 				 * Chain it, skip if
120*1945Sjeanm 				 * already there
1210Sstevel@tonic-gate 				 */
1220Sstevel@tonic-gate 				if (overlap_disks == NULL) {
1230Sstevel@tonic-gate 					set_dr->overlap = NULL;
124*1945Sjeanm 					set_dr->overlapped_disk = 1;
125*1945Sjeanm 					next_set_dr->overlapped_disk = 1;
1260Sstevel@tonic-gate 					overlap_disks = set_dr;
1270Sstevel@tonic-gate 				} else {
1280Sstevel@tonic-gate 				    for (chain = &overlap_disks;
1290Sstevel@tonic-gate 					*chain != NULL;
1300Sstevel@tonic-gate 					chain = &(*chain)->overlap) {
1310Sstevel@tonic-gate 					if (strcmp(set_dr->mid_dnp->cname,
132*1945Sjeanm 					    (*chain)->mid_dnp->cname) == 0)
1330Sstevel@tonic-gate 						break;
1340Sstevel@tonic-gate 				    }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 				    if (*chain == NULL) {
1370Sstevel@tonic-gate 					*chain = set_dr;
1380Sstevel@tonic-gate 					set_dr->overlap = NULL;
139*1945Sjeanm 					set_dr->overlapped_disk = 1;
140*1945Sjeanm 					next_set_dr->overlapped_disk = 1;
1410Sstevel@tonic-gate 				    }
1420Sstevel@tonic-gate 				}
1430Sstevel@tonic-gate 				if (!is_overlap)
1440Sstevel@tonic-gate 					is_overlap = 1;
1450Sstevel@tonic-gate 			}
146*1945Sjeanm 		    }
1470Sstevel@tonic-gate 		}
1480Sstevel@tonic-gate 	    }
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
151*1945Sjeanm 	for (isp = misp; isp != NULL; isp = isp->mis_next) {
152*1945Sjeanm 		good_disk = pick_good_disk(isp);
153*1945Sjeanm 		if (good_disk == NULL) {
154*1945Sjeanm 			/* didn't find a good disk */
155*1945Sjeanm 			continue;
156*1945Sjeanm 		}
157*1945Sjeanm 		gooddisktime = good_disk->mid_setcreatetimestamp;
158*1945Sjeanm 		for (d = isp->mis_drives; d != NULL; d = d->mid_next) {
159*1945Sjeanm 			if (d->mid_available == MD_IM_DISK_NOT_AVAILABLE)
160*1945Sjeanm 				continue;
161*1945Sjeanm 			/*
162*1945Sjeanm 			 * If the disk doesn't have the same set creation
163*1945Sjeanm 			 * time as the designated "good disk" we have a
164*1945Sjeanm 			 * time conflict/overlap situation. Mark the disk
165*1945Sjeanm 			 * as such.
166*1945Sjeanm 			 */
167*1945Sjeanm 			if ((gooddisktime.tv_usec !=
168*1945Sjeanm 			    d->mid_setcreatetimestamp.tv_usec) ||
169*1945Sjeanm 			    (gooddisktime.tv_sec !=
170*1945Sjeanm 			    d->mid_setcreatetimestamp.tv_sec)) {
171*1945Sjeanm 				d->overlapped_disk = 1;
172*1945Sjeanm 				if (overlap_disks == NULL) {
173*1945Sjeanm 					d->overlap = NULL;
174*1945Sjeanm 					d->overlapped_disk = 1;
175*1945Sjeanm 					overlap_disks = d;
176*1945Sjeanm 				} else {
177*1945Sjeanm 					for (chain = &overlap_disks;
178*1945Sjeanm 					    *chain != NULL;
179*1945Sjeanm 					    chain = &(*chain)->overlap) {
180*1945Sjeanm 						if (strcmp(d->mid_dnp->cname,
181*1945Sjeanm 						    (*chain)->mid_dnp->cname)
182*1945Sjeanm 						    == 0) {
183*1945Sjeanm 							break;
184*1945Sjeanm 						}
185*1945Sjeanm 					}
186*1945Sjeanm 
187*1945Sjeanm 					if (*chain == NULL) {
188*1945Sjeanm 						*chain = d;
189*1945Sjeanm 						d->overlap = NULL;
190*1945Sjeanm 						d->overlapped_disk = 1;
191*1945Sjeanm 					}
192*1945Sjeanm 				}
193*1945Sjeanm 				if (!is_overlap)
194*1945Sjeanm 					is_overlap = 1;
195*1945Sjeanm 			}
196*1945Sjeanm 		}
197*1945Sjeanm 	}
1980Sstevel@tonic-gate 	return (is_overlap);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate static void
2020Sstevel@tonic-gate report_overlap_recommendation()
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate 	mddb_mb_t		*mbp;
2050Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
2060Sstevel@tonic-gate 	md_error_t		*ep = &status;
2070Sstevel@tonic-gate 	md_im_drive_info_t	*d;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	(void) fprintf(stdout, "%s\n", gettext("Warning:  The following disks "
2100Sstevel@tonic-gate 	    "have been detected in more than one set.\n"
2110Sstevel@tonic-gate 	    "Import recommendation based upon set creation time.\n"
2120Sstevel@tonic-gate 	    "Proceed with the import with caution."));
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	/*
2150Sstevel@tonic-gate 	 * Look at all overlapping disks. Determine which slice
2160Sstevel@tonic-gate 	 * would have a replica on it. i.e. either slice 7 or 6.
2170Sstevel@tonic-gate 	 * Then read the master block. If the disk doesn't have a
2180Sstevel@tonic-gate 	 * metadb on it, the master block is a dummy master block.
2190Sstevel@tonic-gate 	 * Both dummy or normal master block contain the timestamp
2200Sstevel@tonic-gate 	 * which is what we are after. Use this timestamp to issue
2210Sstevel@tonic-gate 	 * the appropriate recommendation.
2220Sstevel@tonic-gate 	 */
2230Sstevel@tonic-gate 	mbp = Malloc(DEV_BSIZE);
2240Sstevel@tonic-gate 	for (d = overlap_disks; d != NULL; d = d->overlap) {
2250Sstevel@tonic-gate 		mdname_t	*rsp;
2260Sstevel@tonic-gate 		uint_t		sliceno;
2270Sstevel@tonic-gate 		int		fd = -1;
2280Sstevel@tonic-gate 
229*1945Sjeanm 		/*
230*1945Sjeanm 		 * If the disk isn't available (i.e. powered off or dead)
231*1945Sjeanm 		 * we can't read the master block timestamp and thus
232*1945Sjeanm 		 * cannot make a recommendation as to which set it belongs to.
233*1945Sjeanm 		 */
234*1945Sjeanm 		if (d->mid_available != MD_IM_DISK_AVAILABLE) {
235*1945Sjeanm 			(void) fprintf(stdout, "  %s ", d->mid_dnp->cname);
236*1945Sjeanm 			(void) fprintf(stdout,
237*1945Sjeanm 			    gettext(" - no recommendation can "
238*1945Sjeanm 			    "be made because disk is unavailable\n"));
239*1945Sjeanm 			continue;
240*1945Sjeanm 		}
241*1945Sjeanm 
2420Sstevel@tonic-gate 		if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0)
2430Sstevel@tonic-gate 			continue;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 		if (d->mid_dnp->vtoc.parts[sliceno].size == 0)
2460Sstevel@tonic-gate 			continue;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		if ((rsp = metaslicename(d->mid_dnp, sliceno, ep)) == NULL)
2490Sstevel@tonic-gate 			continue;
2500Sstevel@tonic-gate 		if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0)
2510Sstevel@tonic-gate 			continue;
2520Sstevel@tonic-gate 		if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) {
2530Sstevel@tonic-gate 			(void) close(fd);
2540Sstevel@tonic-gate 			mdclrerror(ep);
2550Sstevel@tonic-gate 			continue;
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 		(void) close(fd);
2580Sstevel@tonic-gate 		fprintf(stdout, "  %s ", d->mid_dnp->cname);
2590Sstevel@tonic-gate 		    (void) fprintf(stdout, "%s: %s\n",
260*1945Sjeanm 		    gettext(" - must import with set "
2610Sstevel@tonic-gate 		    "created at "), meta_print_time((md_timeval32_t *)
2620Sstevel@tonic-gate 		    (&(mbp->mb_setcreatetime))));
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	Free(mbp);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
267*1945Sjeanm /*
268*1945Sjeanm  * is_first_disk is called to determine if the disk passed to it is
269*1945Sjeanm  * eligible to be used as the "first disk time" in the set. It checks to
270*1945Sjeanm  * see if the disk is available, on the skip list or not (thus already in
271*1945Sjeanm  * an importable set) or being used by the system already.
272*1945Sjeanm  * RETURN:
273*1945Sjeanm  *	1	The time can be used as the first disk time
274*1945Sjeanm  *	0	The time should not be used.
275*1945Sjeanm  */
276*1945Sjeanm static int
277*1945Sjeanm is_first_disk(
278*1945Sjeanm md_im_drive_info_t	*d,
279*1945Sjeanm mddrivenamelist_t	**skiph)
280*1945Sjeanm {
281*1945Sjeanm 	mddrivenamelist_t	*slp;
282*1945Sjeanm 	md_error_t		status = mdnullerror;
283*1945Sjeanm 	md_error_t		*ep = &status;
284*1945Sjeanm 	mdsetname_t		*sp = metasetname(MD_LOCAL_NAME, ep);
285*1945Sjeanm 
286*1945Sjeanm 	/*
287*1945Sjeanm 	 * If a disk is not available there is no
288*1945Sjeanm 	 * set creation timestamp available.
289*1945Sjeanm 	 */
290*1945Sjeanm 	if (d->mid_available == MD_IM_DISK_AVAILABLE) {
291*1945Sjeanm 		/*
292*1945Sjeanm 		 * We also need to make sure this disk isn't already on
293*1945Sjeanm 		 * the skip list.
294*1945Sjeanm 		 */
295*1945Sjeanm 		for (slp = *skiph; slp != NULL; slp = slp->next) {
296*1945Sjeanm 			if (d->mid_dnp == slp->drivenamep)
297*1945Sjeanm 				return (0);
298*1945Sjeanm 		}
299*1945Sjeanm 		/*
300*1945Sjeanm 		 * And we need to make sure the drive isn't
301*1945Sjeanm 		 * currently being used for something else
302*1945Sjeanm 		 * like a mounted file system or a current
303*1945Sjeanm 		 * metadevice or in a set.
304*1945Sjeanm 		 */
305*1945Sjeanm 		if (meta_imp_drvused(sp, d->mid_dnp, ep)) {
306*1945Sjeanm 			return (0);
307*1945Sjeanm 		}
308*1945Sjeanm 	} else {
309*1945Sjeanm 		return (0);
310*1945Sjeanm 	}
311*1945Sjeanm 	return (1);
312*1945Sjeanm }
313*1945Sjeanm 
314*1945Sjeanm /*
315*1945Sjeanm  * Input a list of disks (dnlp), find the sets that are importable, create
316*1945Sjeanm  * a list of these sets (mispp), and a list of the disks within each of these
317*1945Sjeanm  * sets (midp). These lists (mispp and midp) will be used by metaimport.
318*1945Sjeanm  */
319*1945Sjeanm static int process_disks(
320*1945Sjeanm 	mddrivenamelist_t	*dnlp,
321*1945Sjeanm 	mddrivenamelist_t	**skipt,
322*1945Sjeanm 	md_im_set_desc_t	**mispp,
323*1945Sjeanm 	int			flags,
324*1945Sjeanm 	int			*set_count,
325*1945Sjeanm 	int			overlap,
326*1945Sjeanm 	md_error_t		*ep
327*1945Sjeanm )
328*1945Sjeanm {
329*1945Sjeanm 	mddrivenamelist_t	*dp;
330*1945Sjeanm 	int			rscount = 0;
331*1945Sjeanm 	int			hasreplica;
332*1945Sjeanm 	md_im_set_desc_t	*p;
333*1945Sjeanm 	md_im_drive_info_t	*d;
334*1945Sjeanm 	mddrivenamelist_t	**skiph = skipt;
335*1945Sjeanm 
336*1945Sjeanm 	/* Scan qualified disks */
337*1945Sjeanm 	for (dp = dnlp; dp != NULL; dp = dp->next) {
338*1945Sjeanm 		mddrivenamelist_t *slp;
339*1945Sjeanm 
340*1945Sjeanm 		/* is the current drive on the skip list? */
341*1945Sjeanm 		for (slp = *skiph; slp != NULL; slp = slp->next) {
342*1945Sjeanm 		    if (dp->drivenamep == slp->drivenamep)
343*1945Sjeanm 			    break;
344*1945Sjeanm 		}
345*1945Sjeanm 		/* drive on the skip list ? */
346*1945Sjeanm 		if (slp != NULL)
347*1945Sjeanm 			continue;
348*1945Sjeanm 
349*1945Sjeanm 		/*
350*1945Sjeanm 		 * In addition to updating the misp list, either verbose or
351*1945Sjeanm 		 * standard output will be generated.
352*1945Sjeanm 		 *
353*1945Sjeanm 		 */
354*1945Sjeanm 		hasreplica = meta_get_and_report_set_info(dp, mispp, 0,
355*1945Sjeanm 		    flags, set_count, overlap, overlap_disks, ep);
356*1945Sjeanm 
357*1945Sjeanm 		if (hasreplica < 0) {
358*1945Sjeanm 			mde_perror(ep, "");
359*1945Sjeanm 			mdclrerror(ep);
360*1945Sjeanm 		} else {
361*1945Sjeanm 
362*1945Sjeanm 			rscount += hasreplica;
363*1945Sjeanm 
364*1945Sjeanm 			/* Eliminate duplicate reporting */
365*1945Sjeanm 			if (hasreplica > 0) {
366*1945Sjeanm 				md_timeval32_t	firstdisktime;
367*1945Sjeanm 
368*1945Sjeanm 				/*
369*1945Sjeanm 				 * Go to the tail for the current set
370*1945Sjeanm 				 */
371*1945Sjeanm 				for (p = *mispp; p->mis_next != NULL;
372*1945Sjeanm 				    p = p->mis_next);
373*1945Sjeanm 
374*1945Sjeanm 				/*
375*1945Sjeanm 				 * Now look for the set creation timestamp.
376*1945Sjeanm 				 * If a disk is not available there is no
377*1945Sjeanm 				 * set creation timestamp available so look
378*1945Sjeanm 				 * for the first available disk to grab this
379*1945Sjeanm 				 * information from. We also need to make
380*1945Sjeanm 				 * sure this disk isn't already on the skip
381*1945Sjeanm 				 * list. If so go to the next available drive.
382*1945Sjeanm 				 * And we need to make sure the drive isn't
383*1945Sjeanm 				 * currently being used for something else
384*1945Sjeanm 				 * like a mounted file system or a current
385*1945Sjeanm 				 * metadevice or in a set.
386*1945Sjeanm 				 */
387*1945Sjeanm 				for (d = p->mis_drives; d != NULL;
388*1945Sjeanm 				    d = d->mid_next) {
389*1945Sjeanm 					if (is_first_disk(d, skiph)) {
390*1945Sjeanm 						firstdisktime =
391*1945Sjeanm 						    d->mid_setcreatetimestamp;
392*1945Sjeanm 						break;
393*1945Sjeanm 					}
394*1945Sjeanm 				}
395*1945Sjeanm 				for (d = p->mis_drives; d != NULL;
396*1945Sjeanm 				    d = d->mid_next) {
397*1945Sjeanm 					/*
398*1945Sjeanm 					 * if the mb_setcreatetime for a disk
399*1945Sjeanm 					 * is not the same as the first disk
400*1945Sjeanm 					 * in the set, don't put it on the
401*1945Sjeanm 					 * skip list. This disk probably
402*1945Sjeanm 					 * doesn't really belong in this set
403*1945Sjeanm 					 * and we'll want to look at it again
404*1945Sjeanm 					 * to figure out where it does belong.
405*1945Sjeanm 					 * If the disk isn't available, there's
406*1945Sjeanm 					 * really no point in looking at it
407*1945Sjeanm 					 * again so put it on the skip list.
408*1945Sjeanm 					 */
409*1945Sjeanm 					if (d->mid_available ==
410*1945Sjeanm 					    MD_IM_DISK_AVAILABLE) {
411*1945Sjeanm 						if ((d->mid_setcreatetimestamp.
412*1945Sjeanm 						    tv_sec != firstdisktime.
413*1945Sjeanm 						    tv_sec) ||
414*1945Sjeanm 						    (d->mid_setcreatetimestamp.
415*1945Sjeanm 						    tv_usec !=
416*1945Sjeanm 						    firstdisktime.tv_usec))
417*1945Sjeanm 							continue;
418*1945Sjeanm 					}
419*1945Sjeanm 					skipt =
420*1945Sjeanm 					    meta_drivenamelist_append_wrapper(
421*1945Sjeanm 						skipt, d->mid_dnp);
422*1945Sjeanm 				}
423*1945Sjeanm 			}
424*1945Sjeanm 		}
425*1945Sjeanm 	}
426*1945Sjeanm 	return (rscount);
427*1945Sjeanm }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate int
4300Sstevel@tonic-gate main(int argc, char *argv[])
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate 	char			c;
4330Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
4340Sstevel@tonic-gate 	md_error_t		*ep = &status;
4350Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
4360Sstevel@tonic-gate 	char			*setname_new = NULL;
4370Sstevel@tonic-gate 	int			report_only = 0;
4380Sstevel@tonic-gate 	int			version = 0;
4390Sstevel@tonic-gate 	bool_t			dry_run = 0;
4400Sstevel@tonic-gate 	md_im_names_t		cnames = { 0, NULL };
4410Sstevel@tonic-gate 	int			err_on_prune = 0;
4420Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
4430Sstevel@tonic-gate 	mddrivenamelist_t	*dp;
4440Sstevel@tonic-gate 	mddrivenamelist_t	*skiph = NULL;
4450Sstevel@tonic-gate 	int			rscount = 0;
446*1945Sjeanm 	md_im_set_desc_t	*pass1_misp = NULL;
4470Sstevel@tonic-gate 	md_im_set_desc_t	*misp = NULL;
448*1945Sjeanm 	md_im_set_desc_t	**pass1_mispp = &pass1_misp;
4490Sstevel@tonic-gate 	md_im_set_desc_t	**mispp = &misp;
4500Sstevel@tonic-gate 	mhd_mhiargs_t		mhiargs = defmhiargs;
4510Sstevel@tonic-gate 	int			have_multiple_sets = 0;
4520Sstevel@tonic-gate 	int			force = 0;
4530Sstevel@tonic-gate 	int			overlap = 0;
454734Smw145384 	uint_t			imp_flags = 0;
455734Smw145384 	int			set_count = 0;
456*1945Sjeanm 	int			no_quorum = 0;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
4600Sstevel@tonic-gate 	 * with messages to output.  Just in case we're not in a build
4610Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
4620Sstevel@tonic-gate 	 * something.
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
4650Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
4660Sstevel@tonic-gate #endif
4670Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4680Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/*
4710Sstevel@tonic-gate 	 * Check to see if the libsds_sc.so is bound on the
4720Sstevel@tonic-gate 	 * current system. If it is, it means the system is
4730Sstevel@tonic-gate 	 * part of a cluster.
4740Sstevel@tonic-gate 	 *
4750Sstevel@tonic-gate 	 * The import operation is currently not supported
4760Sstevel@tonic-gate 	 * in a SunCluster environment.
4770Sstevel@tonic-gate 	 */
4780Sstevel@tonic-gate 	if (sdssc_bind_library() != SDSSC_NOT_BOUND) {
4790Sstevel@tonic-gate 		printf(gettext(
4800Sstevel@tonic-gate 		    "%s: Import operation not supported under SunCluster\n"),
4810Sstevel@tonic-gate 		    argv[0]);
4820Sstevel@tonic-gate 		exit(0);
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/* initialize */
4860Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
4870Sstevel@tonic-gate 		mde_perror(ep, "");
4880Sstevel@tonic-gate 		md_exit(sp, 1);
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	optind = 1;
4920Sstevel@tonic-gate 	opterr = 1;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "frns:vV?")) != -1) {
4950Sstevel@tonic-gate 		switch (c) {
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 		case 'f':
4980Sstevel@tonic-gate 			force = 1;
4990Sstevel@tonic-gate 			break;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 		case 'n':
5020Sstevel@tonic-gate 			dry_run = 1;
5030Sstevel@tonic-gate 			break;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		case 'r':
5060Sstevel@tonic-gate 			report_only = 1;
507734Smw145384 			imp_flags |= META_IMP_REPORT;
5080Sstevel@tonic-gate 			break;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		case 's':
5110Sstevel@tonic-gate 			setname_new = optarg;
5120Sstevel@tonic-gate 			break;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 		case 'v':
515734Smw145384 			imp_flags |= META_IMP_VERBOSE;
5160Sstevel@tonic-gate 			break;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 		case 'V':
5190Sstevel@tonic-gate 			version = 1;
5200Sstevel@tonic-gate 			break;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 		case '?':
5230Sstevel@tonic-gate 		default:
5240Sstevel@tonic-gate 			usage(sp, NULL);
5250Sstevel@tonic-gate 			break;
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (version == 1)
5300Sstevel@tonic-gate 		print_version(sp);
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	/* Detect conflicting options */
5330Sstevel@tonic-gate 	if ((dry_run != 0) && (report_only != 0))
5340Sstevel@tonic-gate 		usage(sp, gettext("The -n and -r options conflict."));
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if ((report_only != 0) && (setname_new != NULL))
5370Sstevel@tonic-gate 		usage(sp, gettext("The -r and -s options conflict."));
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if ((report_only == 0) && (setname_new == NULL))
5400Sstevel@tonic-gate 		usage(sp, gettext("You must specify either -r or -s."));
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/* Don't do any real work if we don't have root privilege */
5430Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
5440Sstevel@tonic-gate 		mde_perror(ep, "");
5450Sstevel@tonic-gate 		md_exit(sp, 1);
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
5490Sstevel@tonic-gate 		mde_perror(ep, "");
5500Sstevel@tonic-gate 		if (mdismddberror(ep, MDE_DB_STALE))
5510Sstevel@tonic-gate 			md_exit(sp, 66);
5520Sstevel@tonic-gate 		if (! mdiserror(ep, MDE_MDDB_CKSUM))
5530Sstevel@tonic-gate 			md_exit(sp, 1);
5540Sstevel@tonic-gate 	}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/*
5570Sstevel@tonic-gate 	 * Read remaining arguments into drive name list, otherwise
5580Sstevel@tonic-gate 	 * call routine to list all drives in system.
5590Sstevel@tonic-gate 	 */
5600Sstevel@tonic-gate 	if (argc > optind) {
5610Sstevel@tonic-gate 		int i;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		/* For user specified disks, they MUST not be in use */
5640Sstevel@tonic-gate 		err_on_prune = 1;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		/* All remaining args should be disks */
5670Sstevel@tonic-gate 		cnames.min_count = argc - optind;
5680Sstevel@tonic-gate 		cnames.min_names = Malloc(cnames.min_count * sizeof (char *));
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 		for (i = 0; i < cnames.min_count; i++, optind++) {
5710Sstevel@tonic-gate 			mddrivename_t *dnp;
5720Sstevel@tonic-gate 			dnp = metadrivename(&sp, argv[optind], ep);
5730Sstevel@tonic-gate 			if (dnp == NULL) {
5740Sstevel@tonic-gate 				mde_perror(ep, "");
5750Sstevel@tonic-gate 				md_exit(sp, 1);
5760Sstevel@tonic-gate 			} else {
5770Sstevel@tonic-gate 				cnames.min_names[i] = dnp->rname;
5780Sstevel@tonic-gate 			}
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 	} else {
5810Sstevel@tonic-gate 		if (meta_list_disks(ep, &cnames) != 0) {
5820Sstevel@tonic-gate 			mde_perror(ep, "");
5830Sstevel@tonic-gate 			md_exit(sp, 1);
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/*
5880Sstevel@tonic-gate 	 * If the user specified disks on the command line, min_count will be
5890Sstevel@tonic-gate 	 * greater than zero.  If they didn't, it should be safe to assume that
5900Sstevel@tonic-gate 	 * the system in question has at least one drive detected by the
5910Sstevel@tonic-gate 	 * snapshot code, or we would have barfed earlier initializing the
5920Sstevel@tonic-gate 	 * metadb.
5930Sstevel@tonic-gate 	 */
5940Sstevel@tonic-gate 	assert(cnames.min_count > 0);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/*
5970Sstevel@tonic-gate 	 * Prune the list:
5980Sstevel@tonic-gate 	 * - get rid of drives in current svm configuration
5990Sstevel@tonic-gate 	 * - get rid of mounted drives
6000Sstevel@tonic-gate 	 * - get rid of swap drives
6010Sstevel@tonic-gate 	 * - get rid of drives in other sets
6020Sstevel@tonic-gate 	 *
6030Sstevel@tonic-gate 	 * If drives were specified on the command line, it should be
6040Sstevel@tonic-gate 	 * an error to find in-use disks in the list.  (err_on_prune)
6050Sstevel@tonic-gate 	 *
6060Sstevel@tonic-gate 	 * On return from meta_prune_cnames call, dnlp
6070Sstevel@tonic-gate 	 * will have candidate for replica scan.
6080Sstevel@tonic-gate 	 */
6090Sstevel@tonic-gate 	dnlp = meta_prune_cnames(ep, &cnames, err_on_prune);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	/*
6120Sstevel@tonic-gate 	 * Doctor the drive string in the error structure to list all of the
6130Sstevel@tonic-gate 	 * unused disks, rather than just one.  The output will be done in the
6140Sstevel@tonic-gate 	 * following !mdisok() block.
6150Sstevel@tonic-gate 	 */
6160Sstevel@tonic-gate 	if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) {
6170Sstevel@tonic-gate 		md_ds_error_t		*ip =
6180Sstevel@tonic-gate 		    &ep->info.md_error_info_t_u.ds_error;
6190Sstevel@tonic-gate 		char			*dlist;
6200Sstevel@tonic-gate 		int			sizecnt = 0;
6210Sstevel@tonic-gate 
622*1945Sjeanm 		/* add 1 for null terminator */
623*1945Sjeanm 		sizecnt += strlen(ip->drive) + 1;
6240Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
6250Sstevel@tonic-gate 			sizecnt += 2; /* for the ", " */
6260Sstevel@tonic-gate 			sizecnt += strlen(dp->drivenamep->cname);
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		dlist = Malloc(sizecnt);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 		strlcpy(dlist, ip->drive, sizecnt);
632*1945Sjeanm 
6330Sstevel@tonic-gate 		Free(ip->drive);
6340Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
6350Sstevel@tonic-gate 			strlcat(dlist, ", ", sizecnt);
6360Sstevel@tonic-gate 			strlcat(dlist, dp->drivenamep->cname, sizecnt);
6370Sstevel@tonic-gate 		}
6380Sstevel@tonic-gate 
639*1945Sjeanm 		ip->drive = dlist;
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	/* Don't continue if we're already hosed */
6430Sstevel@tonic-gate 	if (!mdisok(ep)) {
6440Sstevel@tonic-gate 		mde_perror(ep, "");
6450Sstevel@tonic-gate 		md_exit(sp, 1);
6460Sstevel@tonic-gate 	}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	/* ...or if there's nothing to scan */
6490Sstevel@tonic-gate 	if (dnlp == NULL) {
6500Sstevel@tonic-gate 		md_eprintf("%s\n", gettext("no unused disks detected"));
6510Sstevel@tonic-gate 		md_exit(sp, 0);
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
654*1945Sjeanm 	/*
655*1945Sjeanm 	 * META_IMP_PASS1 means gather the info, but don't report.
656*1945Sjeanm 	 */
657*1945Sjeanm 	(void) process_disks(dnlp, &skiph, pass1_mispp,
658*1945Sjeanm 	    imp_flags | META_IMP_PASS1, &set_count, overlap, ep);
6590Sstevel@tonic-gate 
660*1945Sjeanm 	overlap_disks = NULL;
661*1945Sjeanm 	overlap = set_disk_overlap(pass1_misp);
662*1945Sjeanm 	skiph = NULL;
6630Sstevel@tonic-gate 
664*1945Sjeanm 	/*
665*1945Sjeanm 	 * This time call without META_IMP_PASS1 set and we gather
666*1945Sjeanm 	 * and report the information.
667*1945Sjeanm 	 * We need to do this twice because of the overlap detection.
668*1945Sjeanm 	 * The first pass generates a list of disks to detect overlap on.
669*1945Sjeanm 	 * We then do a second pass using that overlap list to generate
670*1945Sjeanm 	 * the report.
671*1945Sjeanm 	 */
672*1945Sjeanm 	rscount = process_disks(dnlp, &skiph, mispp, imp_flags, &set_count,
673*1945Sjeanm 	    overlap, ep);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/*
6760Sstevel@tonic-gate 	 * Now have entire list of disks associated with diskset including
6770Sstevel@tonic-gate 	 * disks listed in mddb locator blocks and namespace. Before importing
6780Sstevel@tonic-gate 	 * diskset need to recheck that none of these disks is already in use.
6790Sstevel@tonic-gate 	 * If a disk is found that is already in use, print error and exit.
6800Sstevel@tonic-gate 	 */
6810Sstevel@tonic-gate 	if (!report_only) {
6820Sstevel@tonic-gate 		md_im_set_desc_t	*p;
6830Sstevel@tonic-gate 		md_im_drive_info_t	*d;
6840Sstevel@tonic-gate 		mddrivename_t		*dnp;
6850Sstevel@tonic-gate 
686*1945Sjeanm 		if (sp == NULL) {
687*1945Sjeanm 			/* Get sp for local set */
688*1945Sjeanm 			if ((sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
689*1945Sjeanm 				mde_perror(ep, "");
690*1945Sjeanm 				meta_free_im_set_desc(misp);
691*1945Sjeanm 				md_exit(sp, 1);
692*1945Sjeanm 			}
693*1945Sjeanm 		}
694*1945Sjeanm 
6950Sstevel@tonic-gate 		for (p = misp; p != NULL; p = p->mis_next) {
6960Sstevel@tonic-gate 			for (d = p->mis_drives; d != NULL; d = d->mid_next) {
6970Sstevel@tonic-gate 				dnp = d->mid_dnp;
698*1945Sjeanm 				if (d->mid_available == MD_IM_DISK_AVAILABLE) {
699*1945Sjeanm 					if (meta_imp_drvused(sp, dnp, ep)) {
700*1945Sjeanm 						(void) mddserror(ep,
701*1945Sjeanm 						    MDE_DS_DRIVEINUSE, 0, NULL,
702*1945Sjeanm 						    dnp->cname, NULL);
703*1945Sjeanm 						mde_perror(ep, "");
704*1945Sjeanm 						meta_free_im_set_desc(misp);
705*1945Sjeanm 						md_exit(sp, 1);
706*1945Sjeanm 					}
707*1945Sjeanm 				} else {
708*1945Sjeanm 					/*
709*1945Sjeanm 					 * If drive is unavailable, then check
710*1945Sjeanm 					 * that this drive hasn't already been
711*1945Sjeanm 					 * imported as part of another partial
712*1945Sjeanm 					 * diskset.  Check by devid instead of
713*1945Sjeanm 					 * cname since the unavailable drive
714*1945Sjeanm 					 * would have the cname from its
715*1945Sjeanm 					 * previous system and this may collide
716*1945Sjeanm 					 * with a valid cname on this system.
717*1945Sjeanm 					 * Fail if devid is found in another
718*1945Sjeanm 					 * set or if the routine fails.
719*1945Sjeanm 					 */
720*1945Sjeanm 					mdsetname_t	*tmp_sp = NULL;
721*1945Sjeanm 
722*1945Sjeanm 					if ((meta_is_devid_in_anyset(
723*1945Sjeanm 					    d->mid_devid, &tmp_sp, ep) == -1) ||
724*1945Sjeanm 					    (tmp_sp != NULL)) {
725*1945Sjeanm 						(void) mddserror(ep,
726*1945Sjeanm 						    MDE_DS_DRIVEINUSE, 0, NULL,
727*1945Sjeanm 						    dnp->cname, NULL);
728*1945Sjeanm 						mde_perror(ep, "");
729*1945Sjeanm 						meta_free_im_set_desc(misp);
730*1945Sjeanm 						md_exit(sp, 1);
731*1945Sjeanm 					}
7320Sstevel@tonic-gate 				}
7330Sstevel@tonic-gate 			}
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	/*
7380Sstevel@tonic-gate 	 * If there are no unconfigured sets, then our work here is done.
7390Sstevel@tonic-gate 	 * Hopefully this is friendlier than just not printing anything at all.
7400Sstevel@tonic-gate 	 */
7410Sstevel@tonic-gate 	if (rscount == 0) {
74257Sjeanm 		/*
74357Sjeanm 		 * If we've found partial disksets but no complete disksets,
74457Sjeanm 		 * we don't want this to print.
74557Sjeanm 		 */
746*1945Sjeanm 		if (!misp) {
74757Sjeanm 			md_eprintf("%s\n", gettext("no unconfigured sets "
74857Sjeanm 			    "detected"));
749*1945Sjeanm 			meta_free_im_set_desc(misp);
750*1945Sjeanm 			md_exit(sp, 1);
75157Sjeanm 		}
7520Sstevel@tonic-gate 		md_exit(sp, 0);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	/*
7560Sstevel@tonic-gate 	 * We'll need this info for both the report content and the import
7570Sstevel@tonic-gate 	 * decision.  By the time we're here, misp should NOT be NULL (or we
7580Sstevel@tonic-gate 	 * would have exited in the rscount == 0 test above).
7590Sstevel@tonic-gate 	 */
7600Sstevel@tonic-gate 	assert(misp != NULL);
7610Sstevel@tonic-gate 	if (misp->mis_next != NULL) {
7620Sstevel@tonic-gate 		have_multiple_sets = 1;
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 	/*
7650Sstevel@tonic-gate 	 * Generate the appropriate (verbose or not) report for all sets
7660Sstevel@tonic-gate 	 * detected.  If we're planning on importing later, only include the
7670Sstevel@tonic-gate 	 * "suggested import" command if multiple sets were detected.  (That
7680Sstevel@tonic-gate 	 * way, when we error out later, we have still provided useful
7690Sstevel@tonic-gate 	 * information.)
7700Sstevel@tonic-gate 	 */
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	/*
7730Sstevel@tonic-gate 	 * Now we should have all the unconfigured sets detected
7740Sstevel@tonic-gate 	 * check for the overlapping
7750Sstevel@tonic-gate 	 */
7760Sstevel@tonic-gate 	if (have_multiple_sets) {
777734Smw145384 		/* Printing out how many candidate disksets we found. */
778734Smw145384 		if (imp_flags & META_IMP_REPORT) {
779734Smw145384 			(void) printf("%s: %i\n\n",
780734Smw145384 			    gettext("Number of disksets eligible for import"),
781734Smw145384 			    set_count);
782734Smw145384 		}
783*1945Sjeanm 	}
784*1945Sjeanm 	if (overlap) {
785*1945Sjeanm 		report_overlap_recommendation();
786*1945Sjeanm 	}
787734Smw145384 
788*1945Sjeanm 	if (have_multiple_sets && !report_only) {
789*1945Sjeanm 		md_eprintf("%s\n\n", gettext("multiple unconfigured "
790*1945Sjeanm 		    "sets detected.\nRerun the command with the "
791*1945Sjeanm 		    "suggested options for the desired set."));
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	/*
7960Sstevel@tonic-gate 	 * If it's a report-only request, we're done.  If it's an import
7970Sstevel@tonic-gate 	 * request, make sure that we only have one entry in the set list.
7980Sstevel@tonic-gate 	 */
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (report_only) {
801*1945Sjeanm 		meta_free_im_set_desc(misp);
8020Sstevel@tonic-gate 		md_exit(sp, 0);
8030Sstevel@tonic-gate 	} else if (have_multiple_sets) {
804*1945Sjeanm 		meta_free_im_set_desc(misp);
805*1945Sjeanm 		md_exit(sp, 1);
806*1945Sjeanm 	} else if (overlap) {
807*1945Sjeanm 		md_im_drive_info_t	*d;
808*1945Sjeanm 		/*
809*1945Sjeanm 		 * The only way we can get here is if we're doing an import
810*1945Sjeanm 		 * request on a set that contains at least one disk with
811*1945Sjeanm 		 * a time conflict. We are prohibiting the importation of
812*1945Sjeanm 		 * this type of set until the offending disk(s) are turned
813*1945Sjeanm 		 * off to prevent data corruption.
814*1945Sjeanm 		 */
815*1945Sjeanm 		printf(gettext("To import this set, "));
816*1945Sjeanm 		for (d = pass1_misp->mis_drives;
817*1945Sjeanm 		    d != NULL;
818*1945Sjeanm 		    d = d->mid_next) {
819*1945Sjeanm 			if (d->overlapped_disk)
820*1945Sjeanm 				printf("%s ", d->mid_dnp->cname);
821*1945Sjeanm 		}
822*1945Sjeanm 		printf(gettext("must be removed from the system\n"));
823*1945Sjeanm 		meta_free_im_set_desc(misp);
8240Sstevel@tonic-gate 		md_exit(sp, 1);
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	if (setname_new == NULL) {
8280Sstevel@tonic-gate 		usage(sp, gettext("You must specify a new set name."));
8290Sstevel@tonic-gate 	}
8300Sstevel@tonic-gate 
831*1945Sjeanm 	/*
832*1945Sjeanm 	 * The user must specify the -f (force) flag if the following
833*1945Sjeanm 	 * conditions exist:
834*1945Sjeanm 	 *		- partial diskset
835*1945Sjeanm 	 *		- stale diskset
836*1945Sjeanm 	 */
837*1945Sjeanm 	if (meta_replica_quorum(misp) != 0)
838*1945Sjeanm 		no_quorum = 1;
839*1945Sjeanm 	if (misp->mis_partial || no_quorum) {
840*1945Sjeanm 		if (!force)
841*1945Sjeanm 			usage(sp, gettext("You must specify the force flag"));
842*1945Sjeanm 	}
8430Sstevel@tonic-gate 	(void) meta_imp_set(misp, setname_new, force, dry_run, ep);
8440Sstevel@tonic-gate 	if (dry_run) {
845*1945Sjeanm 		meta_free_im_set_desc(misp);
8460Sstevel@tonic-gate 		md_exit(sp, 0);
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	if (!mdisok(ep)) {
850*1945Sjeanm 		meta_free_im_set_desc(misp);
8510Sstevel@tonic-gate 		mde_perror(ep, "");
8520Sstevel@tonic-gate 		md_exit(sp, 1);
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	if ((sp = metasetname(setname_new, ep)) == NULL) {
856*1945Sjeanm 		meta_free_im_set_desc(misp);
8570Sstevel@tonic-gate 		mde_perror(ep, "");
8580Sstevel@tonic-gate 		md_exit(sp, 1);
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
862*1945Sjeanm 		meta_free_im_set_desc(misp);
8630Sstevel@tonic-gate 		mde_perror(ep, "");
8640Sstevel@tonic-gate 		md_exit(sp, 10);	/* special errcode */
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 
867*1945Sjeanm 	if (meta_set_take(sp, &mhiargs, (misp->mis_partial | TAKE_IMP),
868*1945Sjeanm 	    0, &status)) {
869*1945Sjeanm 		meta_free_im_set_desc(misp);
8700Sstevel@tonic-gate 		mde_perror(&status, "");
8710Sstevel@tonic-gate 		md_exit(sp, 1);
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
874*1945Sjeanm 	meta_free_im_set_desc(misp);
8750Sstevel@tonic-gate 	md_exit(sp, 0);
8760Sstevel@tonic-gate 	/*NOTREACHED*/
8770Sstevel@tonic-gate 	return (0);
8780Sstevel@tonic-gate }
879