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