xref: /titanic_41/usr/src/cmd/lvm/util/metaimport.c (revision 1f0f5e3e328e41529296f756090856aa7f239b1c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Utility to import SVM disksets into an active SVM configuration.
28  */
29 
30 #include <assert.h>
31 #include <strings.h>
32 #include <string.h>
33 #include <meta.h>
34 #include <sys/utsname.h>
35 #include <sys/lvm/md_mddb.h>
36 #include <sys/lvm/md_names.h>
37 #include <sdssc.h>
38 
39 static md_im_drive_info_t	*overlap_disks;
40 
41 static void
42 usage(mdsetname_t *sp, char *string)
43 {
44 	if ((string != NULL) && (*string != '\0'))
45 		md_eprintf("%s\n", string);
46 
47 	(void) fprintf(stderr,
48 	    "%s:\t%s -s setname [-n] [-f] [-v] [%s...]\n",
49 	    gettext("usage"), myname, gettext("disk"));
50 	(void) fprintf(stderr, "        %s -r [%s...]\n",
51 	    myname, gettext("disk"));
52 	(void) fprintf(stderr, "        %s -?\n", myname);
53 	(void) fprintf(stderr, "        %s -V\n", myname);
54 
55 	md_exit(sp, (string == NULL) ? 0 : 1);
56 }
57 
58 static void
59 print_version(mdsetname_t *sp)
60 {
61 	struct utsname curname;
62 
63 	if (uname(&curname) == -1) {
64 		md_eprintf("%s\n", strerror(errno));
65 		md_exit(sp, 1);
66 	}
67 
68 	(void) fprintf(stderr, "%s %s\n", myname, curname.version);
69 
70 	md_exit(sp, 0);
71 }
72 
73 /*
74  * Returns 0 if there is no overlap, 1 otherwise
75  */
76 static int
77 set_disk_overlap(md_im_set_desc_t *misp)
78 {
79 	md_im_set_desc_t	*next, *isp = misp;
80 	md_im_drive_info_t	*set_dr, *next_set_dr, **chain;
81 	int			is_overlap = 0;
82 	md_im_drive_info_t	*good_disk = NULL;
83 	md_im_drive_info_t	*d;
84 	md_timeval32_t		gooddisktime;
85 	int			disk_not_available = 0;
86 	/*
87 	 * There are 2 ways we could get an "overlap" disk.
88 	 * One is if the ctd's are the same. The other is if
89 	 * the setcreatetimestamp on the disk doesn't agree with the
90 	 * "good" disk in the set. However, if we have a disk that is
91 	 * unavailable and the other instance of the ctd is available we
92 	 * really don't have a conflict. It's just that the unavailable ctd
93 	 * is it's "old" location and the available instance is a current
94 	 * location.
95 	 */
96 	for (; isp != NULL; isp = isp->mis_next) {
97 	    for (next = isp->mis_next; next != NULL; next = next->mis_next) {
98 		for (set_dr = isp->mis_drives; set_dr != NULL;
99 		    set_dr = set_dr->mid_next) {
100 		    if (set_dr->mid_available == MD_IM_DISK_NOT_AVAILABLE)
101 			disk_not_available = 1;
102 		    else
103 			disk_not_available = 0;
104 		    for (next_set_dr = next->mis_drives; next_set_dr != NULL;
105 			next_set_dr = next_set_dr->mid_next) {
106 			if (disk_not_available &&
107 			    (next_set_dr->mid_available
108 			    == MD_IM_DISK_AVAILABLE))
109 				continue;
110 			else if (!disk_not_available &&
111 			    (next_set_dr->mid_available ==
112 			    MD_IM_DISK_NOT_AVAILABLE))
113 				continue;
114 			if (strcmp(set_dr->mid_dnp->cname,
115 			    next_set_dr->mid_dnp->cname) == 0) {
116 				/*
117 				 * Chain it, skip if
118 				 * already there
119 				 */
120 				if (overlap_disks == NULL) {
121 					set_dr->overlap = NULL;
122 					set_dr->overlapped_disk = 1;
123 					next_set_dr->overlapped_disk = 1;
124 					overlap_disks = set_dr;
125 				} else {
126 				    for (chain = &overlap_disks;
127 					*chain != NULL;
128 					chain = &(*chain)->overlap) {
129 					if (strcmp(set_dr->mid_dnp->cname,
130 					    (*chain)->mid_dnp->cname) == 0)
131 						break;
132 				    }
133 
134 				    if (*chain == NULL) {
135 					*chain = set_dr;
136 					set_dr->overlap = NULL;
137 					set_dr->overlapped_disk = 1;
138 					next_set_dr->overlapped_disk = 1;
139 				    }
140 				}
141 				if (!is_overlap)
142 					is_overlap = 1;
143 			}
144 		    }
145 		}
146 	    }
147 	}
148 
149 	for (isp = misp; isp != NULL; isp = isp->mis_next) {
150 		good_disk = pick_good_disk(isp);
151 		if (good_disk == NULL) {
152 			/* didn't find a good disk */
153 			continue;
154 		}
155 		gooddisktime = good_disk->mid_setcreatetimestamp;
156 		for (d = isp->mis_drives; d != NULL; d = d->mid_next) {
157 			if (d->mid_available == MD_IM_DISK_NOT_AVAILABLE)
158 				continue;
159 			/*
160 			 * If the disk doesn't have the same set creation
161 			 * time as the designated "good disk" we have a
162 			 * time conflict/overlap situation. Mark the disk
163 			 * as such.
164 			 */
165 			if ((gooddisktime.tv_usec !=
166 			    d->mid_setcreatetimestamp.tv_usec) ||
167 			    (gooddisktime.tv_sec !=
168 			    d->mid_setcreatetimestamp.tv_sec)) {
169 				d->overlapped_disk = 1;
170 				if (overlap_disks == NULL) {
171 					d->overlap = NULL;
172 					d->overlapped_disk = 1;
173 					overlap_disks = d;
174 				} else {
175 					for (chain = &overlap_disks;
176 					    *chain != NULL;
177 					    chain = &(*chain)->overlap) {
178 						if (strcmp(d->mid_dnp->cname,
179 						    (*chain)->mid_dnp->cname)
180 						    == 0) {
181 							break;
182 						}
183 					}
184 
185 					if (*chain == NULL) {
186 						*chain = d;
187 						d->overlap = NULL;
188 						d->overlapped_disk = 1;
189 					}
190 				}
191 				if (!is_overlap)
192 					is_overlap = 1;
193 			}
194 		}
195 	}
196 	return (is_overlap);
197 }
198 
199 static void
200 report_overlap_recommendation()
201 {
202 	mddb_mb_t		*mbp;
203 	md_error_t		status = mdnullerror;
204 	md_error_t		*ep = &status;
205 	md_im_drive_info_t	*d;
206 
207 	(void) fprintf(stdout, "%s\n", gettext("Warning:  The following disks "
208 	    "have been detected in more than one set.\n"
209 	    "Import recommendation based upon set creation time.\n"
210 	    "Proceed with the import with caution."));
211 
212 	/*
213 	 * Look at all overlapping disks. Determine which slice
214 	 * would have a replica on it. i.e. either slice 7 or 6.
215 	 * Then read the master block. If the disk doesn't have a
216 	 * metadb on it, the master block is a dummy master block.
217 	 * Both dummy or normal master block contain the timestamp
218 	 * which is what we are after. Use this timestamp to issue
219 	 * the appropriate recommendation.
220 	 */
221 	mbp = Malloc(DEV_BSIZE);
222 	for (d = overlap_disks; d != NULL; d = d->overlap) {
223 		mdname_t	*rsp;
224 		uint_t		sliceno;
225 		int		fd = -1;
226 
227 		/*
228 		 * If the disk isn't available (i.e. powered off or dead)
229 		 * we can't read the master block timestamp and thus
230 		 * cannot make a recommendation as to which set it belongs to.
231 		 */
232 		if (d->mid_available != MD_IM_DISK_AVAILABLE) {
233 			(void) fprintf(stdout, "  %s ", d->mid_dnp->cname);
234 			(void) fprintf(stdout,
235 			    gettext(" - no recommendation can "
236 			    "be made because disk is unavailable\n"));
237 			continue;
238 		}
239 
240 		if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0)
241 			continue;
242 
243 		if (d->mid_dnp->vtoc.parts[sliceno].size == 0)
244 			continue;
245 
246 		if ((rsp = metaslicename(d->mid_dnp, sliceno, ep)) == NULL)
247 			continue;
248 		if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0)
249 			continue;
250 		if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) {
251 			(void) close(fd);
252 			mdclrerror(ep);
253 			continue;
254 		}
255 		(void) close(fd);
256 		(void) fprintf(stdout, "  %s ", d->mid_dnp->cname);
257 		(void) fprintf(stdout, "%s: %s\n",
258 		    gettext(" - must import with set "
259 		    "created at "), meta_print_time((md_timeval32_t *)
260 		    (&(mbp->mb_setcreatetime))));
261 	}
262 	Free(mbp);
263 }
264 
265 /*
266  * is_first_disk is called to determine if the disk passed to it is
267  * eligible to be used as the "first disk time" in the set. It checks to
268  * see if the disk is available, on the skip list or not (thus already in
269  * an importable set) or being used by the system already.
270  * RETURN:
271  *	1	The time can be used as the first disk time
272  *	0	The time should not be used.
273  */
274 static int
275 is_first_disk(
276 md_im_drive_info_t	*d,
277 mddrivenamelist_t	**skiph)
278 {
279 	mddrivenamelist_t	*slp;
280 	md_error_t		status = mdnullerror;
281 	md_error_t		*ep = &status;
282 	mdsetname_t		*sp = metasetname(MD_LOCAL_NAME, ep);
283 
284 	/*
285 	 * If a disk is not available there is no
286 	 * set creation timestamp available.
287 	 */
288 	if (d->mid_available == MD_IM_DISK_AVAILABLE) {
289 		/*
290 		 * We also need to make sure this disk isn't already on
291 		 * the skip list.
292 		 */
293 		for (slp = *skiph; slp != NULL; slp = slp->next) {
294 			if (d->mid_dnp == slp->drivenamep)
295 				return (0);
296 		}
297 		/*
298 		 * And we need to make sure the drive isn't
299 		 * currently being used for something else
300 		 * like a mounted file system or a current
301 		 * metadevice or in a set.
302 		 */
303 		if (meta_imp_drvused(sp, d->mid_dnp, ep)) {
304 			return (0);
305 		}
306 	} else {
307 		return (0);
308 	}
309 	return (1);
310 }
311 
312 /*
313  * Input a list of disks (dnlp), find the sets that are importable, create
314  * a list of these sets (mispp), and a list of the disks within each of these
315  * sets (midp). These lists (mispp and midp) will be used by metaimport.
316  */
317 static int process_disks(
318 	mddrivenamelist_t	*dnlp,
319 	mddrivenamelist_t	**skipt,
320 	md_im_set_desc_t	**mispp,
321 	int			flags,
322 	int			*set_count,
323 	int			overlap,
324 	md_error_t		*ep
325 )
326 {
327 	mddrivenamelist_t	*dp;
328 	int			rscount = 0;
329 	int			hasreplica;
330 	md_im_set_desc_t	*p;
331 	md_im_drive_info_t	*d;
332 	mddrivenamelist_t	**skiph = skipt;
333 
334 	/* Scan qualified disks */
335 	for (dp = dnlp; dp != NULL; dp = dp->next) {
336 		mddrivenamelist_t *slp;
337 
338 		/* is the current drive on the skip list? */
339 		for (slp = *skiph; slp != NULL; slp = slp->next) {
340 			if (dp->drivenamep == slp->drivenamep)
341 				break;
342 		}
343 		/* drive on the skip list ? */
344 		if (slp != NULL)
345 			continue;
346 
347 		/*
348 		 * In addition to updating the misp list, either verbose or
349 		 * standard output will be generated.
350 		 *
351 		 */
352 		hasreplica = meta_get_and_report_set_info(dp, mispp, 0,
353 		    flags, set_count, overlap, overlap_disks, ep);
354 
355 		if (hasreplica < 0) {
356 			mde_perror(ep, "");
357 			mdclrerror(ep);
358 		} else {
359 
360 			rscount += hasreplica;
361 
362 			/* Eliminate duplicate reporting */
363 			if (hasreplica > 0) {
364 				md_timeval32_t	firstdisktime;
365 
366 				/*
367 				 * Go to the tail for the current set
368 				 */
369 				for (p = *mispp; p->mis_next != NULL;
370 				    p = p->mis_next)
371 				;
372 
373 				/*
374 				 * Now look for the set creation timestamp.
375 				 * If a disk is not available there is no
376 				 * set creation timestamp available so look
377 				 * for the first available disk to grab this
378 				 * information from. We also need to make
379 				 * sure this disk isn't already on the skip
380 				 * list. If so go to the next available drive.
381 				 * And we need to make sure the drive isn't
382 				 * currently being used for something else
383 				 * like a mounted file system or a current
384 				 * metadevice or in a set.
385 				 */
386 				for (d = p->mis_drives; d != NULL;
387 				    d = d->mid_next) {
388 					if (is_first_disk(d, skiph)) {
389 						firstdisktime =
390 						    d->mid_setcreatetimestamp;
391 						break;
392 					}
393 				}
394 				for (d = p->mis_drives; d != NULL;
395 				    d = d->mid_next) {
396 					/*
397 					 * if the mb_setcreatetime for a disk
398 					 * is not the same as the first disk
399 					 * in the set, don't put it on the
400 					 * skip list. This disk probably
401 					 * doesn't really belong in this set
402 					 * and we'll want to look at it again
403 					 * to figure out where it does belong.
404 					 * If the disk isn't available, there's
405 					 * really no point in looking at it
406 					 * again so put it on the skip list.
407 					 */
408 					if (d->mid_available ==
409 					    MD_IM_DISK_AVAILABLE) {
410 						if ((d->mid_setcreatetimestamp.
411 						    tv_sec != firstdisktime.
412 						    tv_sec) ||
413 						    (d->mid_setcreatetimestamp.
414 						    tv_usec !=
415 						    firstdisktime.tv_usec))
416 							continue;
417 					}
418 					skipt =
419 					    meta_drivenamelist_append_wrapper(
420 					    skipt, d->mid_dnp);
421 				}
422 			}
423 		}
424 	}
425 	return (rscount);
426 }
427 
428 int
429 main(int argc, char *argv[])
430 {
431 	char			c;
432 	md_error_t		status = mdnullerror;
433 	md_error_t		*ep = &status;
434 	mdsetname_t		*sp = NULL;
435 	char			*setname_new = NULL;
436 	int			report_only = 0;
437 	int			version = 0;
438 	bool_t			dry_run = 0;
439 	md_im_names_t		cnames = { 0, NULL };
440 	int			err_on_prune = 0;
441 	mddrivenamelist_t	*dnlp = NULL;
442 	mddrivenamelist_t	*dp;
443 	mddrivenamelist_t	*skiph = NULL;
444 	int			rscount = 0;
445 	md_im_set_desc_t	*pass1_misp = NULL;
446 	md_im_set_desc_t	*misp = NULL;
447 	md_im_set_desc_t	**pass1_mispp = &pass1_misp;
448 	md_im_set_desc_t	**mispp = &misp;
449 	mhd_mhiargs_t		mhiargs = defmhiargs;
450 	int			have_multiple_sets = 0;
451 	int			force = 0;
452 	int			overlap = 0;
453 	uint_t			imp_flags = 0;
454 	int			set_count = 0;
455 	int			no_quorum = 0;
456 
457 	/*
458 	 * Get the locale set up before calling any other routines
459 	 * with messages to output.  Just in case we're not in a build
460 	 * environment, make sure that TEXT_DOMAIN gets set to
461 	 * something.
462 	 */
463 #if !defined(TEXT_DOMAIN)
464 #define	TEXT_DOMAIN "SYS_TEST"
465 #endif
466 	(void) setlocale(LC_ALL, "");
467 	(void) textdomain(TEXT_DOMAIN);
468 
469 	/*
470 	 * Check to see if the libsds_sc.so is bound on the
471 	 * current system. If it is, it means the system is
472 	 * part of a cluster.
473 	 *
474 	 * The import operation is currently not supported
475 	 * in a SunCluster environment.
476 	 */
477 	if (sdssc_bind_library() != SDSSC_NOT_BOUND) {
478 		(void) printf(gettext(
479 		    "%s: Import operation not supported under SunCluster\n"),
480 		    argv[0]);
481 		exit(0);
482 	}
483 
484 	/* initialize */
485 	if (md_init(argc, argv, 0, 1, ep) != 0) {
486 		mde_perror(ep, "");
487 		md_exit(sp, 1);
488 	}
489 
490 	optind = 1;
491 	opterr = 1;
492 
493 	while ((c = getopt(argc, argv, "frns:vV?")) != -1) {
494 		switch (c) {
495 
496 		case 'f':
497 			force = 1;
498 			break;
499 
500 		case 'n':
501 			dry_run = 1;
502 			break;
503 
504 		case 'r':
505 			report_only = 1;
506 			imp_flags |= META_IMP_REPORT;
507 			break;
508 
509 		case 's':
510 			setname_new = optarg;
511 			break;
512 
513 		case 'v':
514 			imp_flags |= META_IMP_VERBOSE;
515 			break;
516 
517 		case 'V':
518 			version = 1;
519 			break;
520 
521 		case '?':
522 		default:
523 			usage(sp, NULL);
524 			break;
525 		}
526 	}
527 
528 	if (version == 1)
529 		print_version(sp);
530 
531 	/* Detect conflicting options */
532 	if ((dry_run != 0) && (report_only != 0))
533 		usage(sp, gettext("The -n and -r options conflict."));
534 
535 	if ((report_only != 0) && (setname_new != NULL))
536 		usage(sp, gettext("The -r and -s options conflict."));
537 
538 	if ((report_only == 0) && (setname_new == NULL))
539 		usage(sp, gettext("You must specify either -r or -s."));
540 
541 	/* Don't do any real work if we don't have root privilege */
542 	if (meta_check_root(ep) != 0) {
543 		mde_perror(ep, "");
544 		md_exit(sp, 1);
545 	}
546 
547 	if (meta_setup_db_locations(ep) != 0) {
548 		mde_perror(ep, "");
549 		if (mdismddberror(ep, MDE_DB_STALE))
550 			md_exit(sp, 66);
551 		if (! mdiserror(ep, MDE_MDDB_CKSUM))
552 			md_exit(sp, 1);
553 	}
554 
555 	/*
556 	 * Read remaining arguments into drive name list, otherwise
557 	 * call routine to list all drives in system.
558 	 */
559 	if (argc > optind) {
560 		int i;
561 
562 		/* For user specified disks, they MUST not be in use */
563 		err_on_prune = 1;
564 
565 		/* All remaining args should be disks */
566 		cnames.min_count = argc - optind;
567 		cnames.min_names = Malloc(cnames.min_count * sizeof (char *));
568 
569 		for (i = 0; i < cnames.min_count; i++, optind++) {
570 			mddrivename_t *dnp;
571 			dnp = metadrivename(&sp, argv[optind], ep);
572 			if (dnp == NULL) {
573 				mde_perror(ep, "");
574 				md_exit(sp, 1);
575 			} else {
576 				cnames.min_names[i] = dnp->rname;
577 			}
578 		}
579 	} else {
580 		if (meta_list_disks(ep, &cnames) != 0) {
581 			mde_perror(ep, "");
582 			md_exit(sp, 1);
583 		}
584 	}
585 
586 	/*
587 	 * If the user specified disks on the command line, min_count will be
588 	 * greater than zero.  If they didn't, it should be safe to assume that
589 	 * the system in question has at least one drive detected by the
590 	 * snapshot code, or we would have barfed earlier initializing the
591 	 * metadb.
592 	 */
593 	assert(cnames.min_count > 0);
594 
595 	/*
596 	 * Prune the list:
597 	 * - get rid of drives in current svm configuration
598 	 * - get rid of mounted drives
599 	 * - get rid of swap drives
600 	 * - get rid of drives in other sets
601 	 *
602 	 * If drives were specified on the command line, it should be
603 	 * an error to find in-use disks in the list.  (err_on_prune)
604 	 *
605 	 * On return from meta_prune_cnames call, dnlp
606 	 * will have candidate for replica scan.
607 	 */
608 	dnlp = meta_prune_cnames(ep, &cnames, err_on_prune);
609 
610 	/*
611 	 * Doctor the drive string in the error structure to list all of the
612 	 * unused disks, rather than just one.  The output will be done in the
613 	 * following !mdisok() block.
614 	 */
615 	if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) {
616 		md_ds_error_t		*ip =
617 		    &ep->info.md_error_info_t_u.ds_error;
618 		char			*dlist;
619 		int			sizecnt = 0;
620 
621 		/* add 1 for null terminator */
622 		sizecnt += strlen(ip->drive) + 1;
623 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
624 			sizecnt += 2; /* for the ", " */
625 			sizecnt += strlen(dp->drivenamep->cname);
626 		}
627 
628 		dlist = Malloc(sizecnt);
629 
630 		(void) strlcpy(dlist, ip->drive, sizecnt);
631 
632 		Free(ip->drive);
633 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
634 			(void) strlcat(dlist, ", ", sizecnt);
635 			(void) strlcat(dlist, dp->drivenamep->cname, sizecnt);
636 		}
637 
638 		ip->drive = dlist;
639 	}
640 
641 	/* Don't continue if we're already hosed */
642 	if (!mdisok(ep)) {
643 		mde_perror(ep, "");
644 		md_exit(sp, 1);
645 	}
646 
647 	/* ...or if there's nothing to scan */
648 	if (dnlp == NULL) {
649 		md_eprintf("%s\n", gettext("no unused disks detected"));
650 		md_exit(sp, 0);
651 	}
652 
653 	/*
654 	 * META_IMP_PASS1 means gather the info, but don't report.
655 	 */
656 	(void) process_disks(dnlp, &skiph, pass1_mispp,
657 	    imp_flags | META_IMP_PASS1, &set_count, overlap, ep);
658 
659 	overlap_disks = NULL;
660 	overlap = set_disk_overlap(pass1_misp);
661 	skiph = NULL;
662 
663 	/*
664 	 * This time call without META_IMP_PASS1 set and we gather
665 	 * and report the information.
666 	 * We need to do this twice because of the overlap detection.
667 	 * The first pass generates a list of disks to detect overlap on.
668 	 * We then do a second pass using that overlap list to generate
669 	 * the report.
670 	 */
671 	rscount = process_disks(dnlp, &skiph, mispp, imp_flags, &set_count,
672 	    overlap, ep);
673 
674 	/*
675 	 * Now have entire list of disks associated with diskset including
676 	 * disks listed in mddb locator blocks and namespace. Before importing
677 	 * diskset need to recheck that none of these disks is already in use.
678 	 * If a disk is found that is already in use, print error and exit.
679 	 */
680 	if (!report_only) {
681 		md_im_set_desc_t	*p;
682 		md_im_drive_info_t	*d;
683 		mddrivename_t		*dnp;
684 
685 		if (sp == NULL) {
686 			/* Get sp for local set */
687 			if ((sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
688 				mde_perror(ep, "");
689 				meta_free_im_set_desc(misp);
690 				md_exit(sp, 1);
691 			}
692 		}
693 
694 		for (p = misp; p != NULL; p = p->mis_next) {
695 			for (d = p->mis_drives; d != NULL; d = d->mid_next) {
696 				dnp = d->mid_dnp;
697 				if (d->mid_available == MD_IM_DISK_AVAILABLE) {
698 					if (meta_imp_drvused(sp, dnp, ep)) {
699 						(void) mddserror(ep,
700 						    MDE_DS_DRIVEINUSE, 0, NULL,
701 						    dnp->cname, NULL);
702 						mde_perror(ep, "");
703 						meta_free_im_set_desc(misp);
704 						md_exit(sp, 1);
705 					}
706 				} else {
707 					/*
708 					 * If drive is unavailable, then check
709 					 * that this drive hasn't already been
710 					 * imported as part of another partial
711 					 * diskset.  Check by devid instead of
712 					 * cname since the unavailable drive
713 					 * would have the cname from its
714 					 * previous system and this may collide
715 					 * with a valid cname on this system.
716 					 * Fail if devid is found in another
717 					 * set or if the routine fails.
718 					 */
719 					mdsetname_t	*tmp_sp = NULL;
720 
721 					if ((meta_is_devid_in_anyset(
722 					    d->mid_devid, &tmp_sp, ep) == -1) ||
723 					    (tmp_sp != NULL)) {
724 						(void) mddserror(ep,
725 						    MDE_DS_DRIVEINUSE, 0, NULL,
726 						    dnp->cname, NULL);
727 						mde_perror(ep, "");
728 						meta_free_im_set_desc(misp);
729 						md_exit(sp, 1);
730 					}
731 				}
732 			}
733 		}
734 	}
735 
736 	/*
737 	 * If there are no unconfigured sets, then our work here is done.
738 	 * Hopefully this is friendlier than just not printing anything at all.
739 	 */
740 	if (rscount == 0) {
741 		/*
742 		 * If we've found partial disksets but no complete disksets,
743 		 * we don't want this to print.
744 		 */
745 		if (!misp) {
746 			md_eprintf("%s\n", gettext("no unconfigured sets "
747 			    "detected"));
748 			meta_free_im_set_desc(misp);
749 			md_exit(sp, 1);
750 		}
751 		md_exit(sp, 0);
752 	}
753 
754 	/*
755 	 * We'll need this info for both the report content and the import
756 	 * decision.  By the time we're here, misp should NOT be NULL (or we
757 	 * would have exited in the rscount == 0 test above).
758 	 */
759 	assert(misp != NULL);
760 	if (misp->mis_next != NULL) {
761 		have_multiple_sets = 1;
762 	}
763 	/*
764 	 * Generate the appropriate (verbose or not) report for all sets
765 	 * detected.  If we're planning on importing later, only include the
766 	 * "suggested import" command if multiple sets were detected.  (That
767 	 * way, when we error out later, we have still provided useful
768 	 * information.)
769 	 */
770 
771 	/*
772 	 * Now we should have all the unconfigured sets detected
773 	 * check for the overlapping
774 	 */
775 	if (have_multiple_sets) {
776 		/* Printing out how many candidate disksets we found. */
777 		if (imp_flags & META_IMP_REPORT) {
778 			(void) printf("%s: %i\n\n",
779 			    gettext("Number of disksets eligible for import"),
780 			    set_count);
781 		}
782 	}
783 	if (overlap) {
784 		report_overlap_recommendation();
785 	}
786 
787 	if (have_multiple_sets && !report_only) {
788 		md_eprintf("%s\n\n", gettext("multiple unconfigured "
789 		    "sets detected.\nRerun the command with the "
790 		    "suggested options for the desired set."));
791 	}
792 
793 
794 	/*
795 	 * If it's a report-only request, we're done.  If it's an import
796 	 * request, make sure that we only have one entry in the set list.
797 	 */
798 
799 	if (report_only) {
800 		meta_free_im_set_desc(misp);
801 		md_exit(sp, 0);
802 	} else if (have_multiple_sets) {
803 		meta_free_im_set_desc(misp);
804 		md_exit(sp, 1);
805 	} else if (overlap) {
806 		md_im_drive_info_t	*d;
807 		/*
808 		 * The only way we can get here is if we're doing an import
809 		 * request on a set that contains at least one disk with
810 		 * a time conflict. We are prohibiting the importation of
811 		 * this type of set until the offending disk(s) are turned
812 		 * off to prevent data corruption.
813 		 */
814 		(void) printf(gettext("To import this set, "));
815 		for (d = pass1_misp->mis_drives;
816 		    d != NULL;
817 		    d = d->mid_next) {
818 			if (d->overlapped_disk)
819 				(void) printf("%s ", d->mid_dnp->cname);
820 		}
821 		(void) printf(gettext("must be removed from the system\n"));
822 		meta_free_im_set_desc(misp);
823 		md_exit(sp, 1);
824 	}
825 
826 	if (setname_new == NULL) {
827 		usage(sp, gettext("You must specify a new set name."));
828 	}
829 
830 	/*
831 	 * The user must specify the -f (force) flag if the following
832 	 * conditions exist:
833 	 *		- partial diskset
834 	 *		- stale diskset
835 	 */
836 	if (meta_replica_quorum(misp) != 0)
837 		no_quorum = 1;
838 	if (misp->mis_partial || no_quorum) {
839 		if (!force)
840 			usage(sp, gettext("You must specify the force flag"));
841 	}
842 	(void) meta_imp_set(misp, setname_new, force, dry_run, ep);
843 	if (dry_run) {
844 		meta_free_im_set_desc(misp);
845 		md_exit(sp, 0);
846 	}
847 
848 	if (!mdisok(ep)) {
849 		meta_free_im_set_desc(misp);
850 		mde_perror(ep, "");
851 		md_exit(sp, 1);
852 	}
853 
854 	if ((sp = metasetname(setname_new, ep)) == NULL) {
855 		meta_free_im_set_desc(misp);
856 		mde_perror(ep, "");
857 		md_exit(sp, 1);
858 	}
859 
860 	if (meta_lock_nowait(sp, ep) != 0) {
861 		meta_free_im_set_desc(misp);
862 		mde_perror(ep, "");
863 		md_exit(sp, 10);	/* special errcode */
864 	}
865 
866 	if (meta_set_take(sp, &mhiargs, (misp->mis_partial | TAKE_IMP),
867 	    0, &status)) {
868 		meta_free_im_set_desc(misp);
869 		mde_perror(&status, "");
870 		md_exit(sp, 1);
871 	}
872 
873 	meta_free_im_set_desc(misp);
874 	md_exit(sp, 0);
875 	/*NOTREACHED*/
876 	return (0);
877 }
878