xref: /onnv-gate/usr/src/cmd/lvm/util/metaimport.c (revision 57:87d369b1608e)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Utility to import SVM disksets into an active SVM configuration.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <assert.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <meta.h>
370Sstevel@tonic-gate #include <sys/utsname.h>
380Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
390Sstevel@tonic-gate #include <sys/lvm/md_names.h>
400Sstevel@tonic-gate #include <sdssc.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static md_im_drive_info_t	*overlap_disks = NULL;
430Sstevel@tonic-gate 
440Sstevel@tonic-gate static void
450Sstevel@tonic-gate usage(mdsetname_t *sp, char *string)
460Sstevel@tonic-gate {
470Sstevel@tonic-gate 	if ((string != NULL) && (*string != '\0'))
480Sstevel@tonic-gate 		md_eprintf("%s\n", string);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	(void) fprintf(stderr,
510Sstevel@tonic-gate 	    "%s:\t%s -s setname [-n] [-f] [-v] [%s...]\n",
520Sstevel@tonic-gate 	    gettext("usage"), myname, gettext("disk"));
530Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -r [%s...]\n",
540Sstevel@tonic-gate 	    myname, gettext("disk"));
550Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -?\n", myname);
560Sstevel@tonic-gate 	(void) fprintf(stderr, "        %s -V\n", myname);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	md_exit(sp, (string == NULL) ? 0 : 1);
590Sstevel@tonic-gate }
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static void
620Sstevel@tonic-gate print_version(mdsetname_t *sp)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate 	struct utsname curname;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	if (uname(&curname) == -1) {
670Sstevel@tonic-gate 		md_eprintf("%s\n", strerror(errno));
680Sstevel@tonic-gate 		md_exit(sp, 1);
690Sstevel@tonic-gate 	}
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	(void) fprintf(stderr, "%s %s\n", myname, curname.version);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	md_exit(sp, 0);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * Returns 0 if there is no overlap, 1 otherwise
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate static int
800Sstevel@tonic-gate set_disk_overlap(md_im_set_desc_t *misp)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	md_im_set_desc_t *next, *isp = misp;
840Sstevel@tonic-gate 	md_im_drive_info_t *set_dr, *next_set_dr, **chain;
850Sstevel@tonic-gate 	int	is_overlap = 0;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	for (; isp != NULL; isp = isp->mis_next) {
880Sstevel@tonic-gate 	    for (next = isp->mis_next; next != NULL; next = next->mis_next) {
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 		for (set_dr = isp->mis_drives; set_dr != NULL;
910Sstevel@tonic-gate 			set_dr = set_dr->mid_next) {
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 			for (next_set_dr = next->mis_drives;
940Sstevel@tonic-gate 			    next_set_dr != NULL;
950Sstevel@tonic-gate 			    next_set_dr = next_set_dr->mid_next) {
960Sstevel@tonic-gate 			    if (strcmp(set_dr->mid_dnp->cname,
970Sstevel@tonic-gate 				next_set_dr->mid_dnp->cname) == 0) {
980Sstevel@tonic-gate 				/*
990Sstevel@tonic-gate 				 * Chain it, skip if already there
1000Sstevel@tonic-gate 				 */
1010Sstevel@tonic-gate 				if (overlap_disks == NULL) {
1020Sstevel@tonic-gate 					set_dr->overlap = NULL;
1030Sstevel@tonic-gate 					overlap_disks = set_dr;
1040Sstevel@tonic-gate 				} else {
1050Sstevel@tonic-gate 				    for (chain = &overlap_disks;
1060Sstevel@tonic-gate 					*chain != NULL;
1070Sstevel@tonic-gate 					chain = &(*chain)->overlap) {
1080Sstevel@tonic-gate 					if (strcmp(set_dr->mid_dnp->cname,
1090Sstevel@tonic-gate 					    (*chain)->mid_dnp->cname)
1100Sstevel@tonic-gate 					    == 0)
1110Sstevel@tonic-gate 						break;
1120Sstevel@tonic-gate 				    }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 				    if (*chain == NULL) {
1150Sstevel@tonic-gate 					*chain = set_dr;
1160Sstevel@tonic-gate 					set_dr->overlap = NULL;
1170Sstevel@tonic-gate 				    }
1180Sstevel@tonic-gate 				}
1190Sstevel@tonic-gate 				if (!is_overlap)
1200Sstevel@tonic-gate 					is_overlap = 1;
1210Sstevel@tonic-gate 			    }
1220Sstevel@tonic-gate 			}
1230Sstevel@tonic-gate 		}
1240Sstevel@tonic-gate 	    }
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	return (is_overlap);
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate static void
1310Sstevel@tonic-gate report_overlap_recommendation()
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	mddb_mb_t		*mbp;
1340Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
1350Sstevel@tonic-gate 	md_error_t		*ep = &status;
1360Sstevel@tonic-gate 	md_im_drive_info_t	*d;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	(void) fprintf(stdout, "%s\n", gettext("Warning:  The following disks "
1390Sstevel@tonic-gate 	    "have been detected in more than one set.\n"
1400Sstevel@tonic-gate 	    "Import recommendation based upon set creation time.\n"
1410Sstevel@tonic-gate 	    "Proceed with the import with caution."));
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	/*
1440Sstevel@tonic-gate 	 * Look at all overlapping disks. Determine which slice
1450Sstevel@tonic-gate 	 * would have a replica on it. i.e. either slice 7 or 6.
1460Sstevel@tonic-gate 	 * Then read the master block. If the disk doesn't have a
1470Sstevel@tonic-gate 	 * metadb on it, the master block is a dummy master block.
1480Sstevel@tonic-gate 	 * Both dummy or normal master block contain the timestamp
1490Sstevel@tonic-gate 	 * which is what we are after. Use this timestamp to issue
1500Sstevel@tonic-gate 	 * the appropriate recommendation.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	mbp = Malloc(DEV_BSIZE);
1530Sstevel@tonic-gate 	for (d = overlap_disks; d != NULL; d = d->overlap) {
1540Sstevel@tonic-gate 		mdname_t	*rsp;
1550Sstevel@tonic-gate 		uint_t		sliceno;
1560Sstevel@tonic-gate 		int		fd = -1;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 		if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0)
1590Sstevel@tonic-gate 			continue;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 		if (d->mid_dnp->vtoc.parts[sliceno].size == 0)
1620Sstevel@tonic-gate 			continue;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		if ((rsp = metaslicename(d->mid_dnp, sliceno, ep)) == NULL)
1650Sstevel@tonic-gate 			continue;
1660Sstevel@tonic-gate 		if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0)
1670Sstevel@tonic-gate 			continue;
1680Sstevel@tonic-gate 		if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) {
1690Sstevel@tonic-gate 			(void) close(fd);
1700Sstevel@tonic-gate 			mdclrerror(ep);
1710Sstevel@tonic-gate 			continue;
1720Sstevel@tonic-gate 		}
1730Sstevel@tonic-gate 		(void) close(fd);
1740Sstevel@tonic-gate 		fprintf(stdout, "  %s ", d->mid_dnp->cname);
1750Sstevel@tonic-gate 		    (void) fprintf(stdout, "%s: %s\n",
1760Sstevel@tonic-gate 		    gettext(" - recommend importing with set "
1770Sstevel@tonic-gate 		    "created at "), meta_print_time((md_timeval32_t *)
1780Sstevel@tonic-gate 		    (&(mbp->mb_setcreatetime))));
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 	Free(mbp);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static void
1840Sstevel@tonic-gate report_standard(md_im_set_desc_t *s, int do_cmd, int overlap)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	md_im_drive_info_t	*d;
1870Sstevel@tonic-gate 	md_im_replica_info_t	*r;
1880Sstevel@tonic-gate 	md_im_drive_info_t	*good_disk = NULL;
1890Sstevel@tonic-gate 	int			i;
1900Sstevel@tonic-gate 	md_timeval32_t		firstdisktime;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	for (i = 0; s != NULL; s = s->mis_next, i++) {
1930Sstevel@tonic-gate 		int	time_conflict = 0;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 		/* Choose the best drive to use for the import command */
1960Sstevel@tonic-gate 		for (good_disk = NULL, d = s->mis_drives;
1970Sstevel@tonic-gate 		    d != NULL; d = d->mid_next) {
1980Sstevel@tonic-gate 			if (good_disk == NULL) {
1990Sstevel@tonic-gate 				for (r = d->mid_replicas;
2000Sstevel@tonic-gate 				    r != NULL;
2010Sstevel@tonic-gate 				    r = r->mir_next) {
2020Sstevel@tonic-gate 					if (r->mir_flags & MDDB_F_ACTIVE) {
2030Sstevel@tonic-gate 						good_disk = d;
2040Sstevel@tonic-gate 						break;
2050Sstevel@tonic-gate 					}
2060Sstevel@tonic-gate 				}
2070Sstevel@tonic-gate 			}
2080Sstevel@tonic-gate 		}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		/*
2110Sstevel@tonic-gate 		 * Make the distinction between a regular diskset and
2120Sstevel@tonic-gate 		 * a replicated diskset.
2130Sstevel@tonic-gate 		 */
2140Sstevel@tonic-gate 		if (s->mis_flags & MD_IM_SET_REPLICATED) {
2150Sstevel@tonic-gate 			(void) fprintf(stdout, "%s :\n",
2160Sstevel@tonic-gate 			gettext("Replicated diskset found containing disks"));
2170Sstevel@tonic-gate 		} else {
2180Sstevel@tonic-gate 			(void) fprintf(stdout, "%s :\n",
2190Sstevel@tonic-gate 			gettext("Regular diskset found containing disks"));
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 		/*
2240Sstevel@tonic-gate 		 * Save the set creation time from the first disk in the
2250Sstevel@tonic-gate 		 * diskset and compare the set creation time on all other
2260Sstevel@tonic-gate 		 * disks in the set to that. If they are the same, the
2270Sstevel@tonic-gate 		 * disk really belongs here. If they are different the
2280Sstevel@tonic-gate 		 * disk probably belongs to a different set and we'll
2290Sstevel@tonic-gate 		 * need to print out a warning.
2300Sstevel@tonic-gate 		 */
2310Sstevel@tonic-gate 		firstdisktime = s->mis_drives->mid_setcreatetimestamp;
2320Sstevel@tonic-gate 		for (d = s->mis_drives; d != NULL; d = d->mid_next) {
2330Sstevel@tonic-gate 			if ((firstdisktime.tv_sec ==
2340Sstevel@tonic-gate 			    d->mid_setcreatetimestamp.tv_sec) &&
2350Sstevel@tonic-gate 			    (firstdisktime.tv_usec ==
2360Sstevel@tonic-gate 			    d->mid_setcreatetimestamp.tv_usec)) {
2370Sstevel@tonic-gate 				(void) fprintf(stdout, "  %s\n",
2380Sstevel@tonic-gate 				    d->mid_dnp->cname);
2390Sstevel@tonic-gate 			} else {
2400Sstevel@tonic-gate 				(void) fprintf(stdout, "  %s *\n",
2410Sstevel@tonic-gate 				    d->mid_dnp->cname);
2420Sstevel@tonic-gate 				time_conflict = 1;
2430Sstevel@tonic-gate 			}
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		if (time_conflict) {
2470Sstevel@tonic-gate 			fprintf(stdout, "* WARNING: This disk has been reused "
2480Sstevel@tonic-gate 			    "in another set.\n  Import may corrupt data in the "
2490Sstevel@tonic-gate 			    "disk set.\n");
2500Sstevel@tonic-gate 		}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		if (overlap) {
2530Sstevel@tonic-gate 			(void) fprintf(stdout, "%s: %s\n",
2540Sstevel@tonic-gate 			    gettext("Diskset creation time"),
2550Sstevel@tonic-gate 		    meta_print_time(&s->mis_drives->mid_replicas->
2560Sstevel@tonic-gate 			mir_timestamp));
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 		/*
2600Sstevel@tonic-gate 		 * when do_cmd is true, we are not actually importing
2610Sstevel@tonic-gate 		 * a disk set, but want to print out extra information
2620Sstevel@tonic-gate 		 */
2630Sstevel@tonic-gate 		if (do_cmd) {
2640Sstevel@tonic-gate 			/*
2650Sstevel@tonic-gate 			 * TRANSLATION_NOTE
2660Sstevel@tonic-gate 			 *
2670Sstevel@tonic-gate 			 * The translation of the phrase "For more information
2680Sstevel@tonic-gate 			 * about this set" will be followed by a ":" and a
2690Sstevel@tonic-gate 			 * suggested command (untranslatable) that the user
2700Sstevel@tonic-gate 			 * may use to request additional information.
2710Sstevel@tonic-gate 			 */
2720Sstevel@tonic-gate 			(void) fprintf(stdout, "%s:\n  %s -r -v %s\n",
2730Sstevel@tonic-gate 			    gettext("For more information about this set"),
2740Sstevel@tonic-gate 			    myname, good_disk->mid_dnp->cname);
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 			/*
2770Sstevel@tonic-gate 			 * TRANSLATION_NOTE
2780Sstevel@tonic-gate 			 *
2790Sstevel@tonic-gate 			 * The translation of the phrase "To import this set"
2800Sstevel@tonic-gate 			 * will be followed by a ":" and a suggested command
2810Sstevel@tonic-gate 			 * (untranslatable) that the user may use to import
2820Sstevel@tonic-gate 			 * the specified diskset.
2830Sstevel@tonic-gate 			 */
2840Sstevel@tonic-gate 			(void) fprintf(stdout, "%s:\n  %s -s <newsetname> %s\n",
2850Sstevel@tonic-gate 			    gettext("To import this set"), myname,
2860Sstevel@tonic-gate 			    good_disk->mid_dnp->cname);
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 		(void) fprintf(stdout, "\n");
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	if (overlap) {
2930Sstevel@tonic-gate 		report_overlap_recommendation();
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate static void
2980Sstevel@tonic-gate report_verbose(md_im_set_desc_t *s, int do_cmd, int overlap)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	md_im_drive_info_t	*d;
3010Sstevel@tonic-gate 	md_im_replica_info_t	*r;
3020Sstevel@tonic-gate 	md_im_drive_info_t	*good_disk;
3030Sstevel@tonic-gate 	static const char	fmt1[] = "%-*.*s %12.12s %12.12s %s\n";
3040Sstevel@tonic-gate 	static const char	fmt2[] = "%-*.*s %12d %12d ";
3050Sstevel@tonic-gate 	int			dlen = 0;
3060Sstevel@tonic-gate 	int			f;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	for (; s != NULL; s = s->mis_next) {
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		/*
3110Sstevel@tonic-gate 		 * Run through the drives in this set to find the one with the
3120Sstevel@tonic-gate 		 * longest common name and the one we want to consider "best"
3130Sstevel@tonic-gate 		 */
3140Sstevel@tonic-gate 		for (d = s->mis_drives, good_disk = NULL;
3150Sstevel@tonic-gate 		    d != NULL; d = d->mid_next) {
3160Sstevel@tonic-gate 			dlen = max(dlen, strlen(d->mid_dnp->cname));
3170Sstevel@tonic-gate 			for (r = d->mid_replicas; r != NULL; r = r->mir_next) {
3180Sstevel@tonic-gate 				if ((good_disk == NULL) &&
3190Sstevel@tonic-gate 				    (r->mir_flags & MDDB_F_ACTIVE)) {
3200Sstevel@tonic-gate 					good_disk = d;
3210Sstevel@tonic-gate 					break;
3220Sstevel@tonic-gate 				}
3230Sstevel@tonic-gate 			}
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		if (do_cmd) {
3270Sstevel@tonic-gate 			(void) fprintf(stdout, "%s: %s -s <newsetname> %s\n",
3280Sstevel@tonic-gate 				gettext("To import this set"), myname,
3290Sstevel@tonic-gate 				good_disk->mid_dnp->cname);
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		(void) fprintf(stdout, "%s: %s\n", gettext("Last update"),
3330Sstevel@tonic-gate 		    meta_print_time(&good_disk->mid_replicas->mir_timestamp));
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		/* Make sure the length will hold the column heading */
3370Sstevel@tonic-gate 		dlen = max(dlen, strlen(gettext("Device")));
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		(void) fprintf(stdout, fmt1, dlen, dlen, gettext("Device"),
3400Sstevel@tonic-gate 		    gettext("offset"), gettext("length"),
3410Sstevel@tonic-gate 		    gettext("replica flags"));
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 		for (d = s->mis_drives; d != NULL; d = d->mid_next) {
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 			if (d->mid_replicas != NULL) {
3460Sstevel@tonic-gate 				for (r = d->mid_replicas;
3470Sstevel@tonic-gate 				    r != NULL;
3480Sstevel@tonic-gate 				    r = r->mir_next) {
3490Sstevel@tonic-gate 					(void) fprintf(stdout, fmt2, dlen, dlen,
3500Sstevel@tonic-gate 					    (r == d->mid_replicas) ?
3510Sstevel@tonic-gate 					    d->mid_dnp->cname : "",
3520Sstevel@tonic-gate 					    r->mir_offset, r->mir_length);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 					for (f = 0; f < MDDB_FLAGS_LEN; f++) {
3550Sstevel@tonic-gate 						(void) putchar(
3560Sstevel@tonic-gate 						    (r->mir_flags & (1 << f)) ?
3570Sstevel@tonic-gate 						    MDDB_FLAGS_STRING[f] : ' ');
3580Sstevel@tonic-gate 					}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 					(void) fprintf(stdout, "\n");
3610Sstevel@tonic-gate 				}
3620Sstevel@tonic-gate 			} else {
3630Sstevel@tonic-gate 				(void) fprintf(stdout, fmt1,
3640Sstevel@tonic-gate 				    dlen, dlen, d->mid_dnp->cname,
3650Sstevel@tonic-gate 				    gettext("no replicas"), "", "");
3660Sstevel@tonic-gate 			}
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		if (overlap) {
3700Sstevel@tonic-gate 			(void) fprintf(stdout, "%s: %s\n",
3710Sstevel@tonic-gate 			    gettext("Diskset creation time"),
3720Sstevel@tonic-gate 		    meta_print_time(&s->mis_drives->mid_replicas->
3730Sstevel@tonic-gate 			mir_timestamp));
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 		(void) fprintf(stdout, "\n");
3770Sstevel@tonic-gate 	}
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	if (overlap) {
3800Sstevel@tonic-gate 		report_overlap_recommendation();
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate int
3850Sstevel@tonic-gate main(int argc, char *argv[])
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	char			c;
3880Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
3890Sstevel@tonic-gate 	md_error_t		*ep = &status;
3900Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
3910Sstevel@tonic-gate 	char			*setname_new = NULL;
3920Sstevel@tonic-gate 	int			report_only = 0;
3930Sstevel@tonic-gate 	int			verbose = 0;
3940Sstevel@tonic-gate 	int			version = 0;
3950Sstevel@tonic-gate 	bool_t			dry_run = 0;
3960Sstevel@tonic-gate 	md_im_names_t		cnames = { 0, NULL };
3970Sstevel@tonic-gate 	int			err_on_prune = 0;
3980Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
3990Sstevel@tonic-gate 	mddrivenamelist_t	*dp;
4000Sstevel@tonic-gate 	mddrivenamelist_t	*skiph = NULL;
4010Sstevel@tonic-gate 	mddrivenamelist_t	**skipt = &skiph;
4020Sstevel@tonic-gate 	int			rscount = 0;
4030Sstevel@tonic-gate 	int			hasreplica;
4040Sstevel@tonic-gate 	md_im_set_desc_t	*misp = NULL;
4050Sstevel@tonic-gate 	md_im_set_desc_t	**mispp = &misp;
4060Sstevel@tonic-gate 	mhd_mhiargs_t		mhiargs = defmhiargs;
4070Sstevel@tonic-gate 	int			have_multiple_sets = 0;
4080Sstevel@tonic-gate 	int			force = 0;
4090Sstevel@tonic-gate 	int			overlap = 0;
4100Sstevel@tonic-gate 	int			partial = 0;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
4140Sstevel@tonic-gate 	 * with messages to output.  Just in case we're not in a build
4150Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
4160Sstevel@tonic-gate 	 * something.
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
4190Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
4200Sstevel@tonic-gate #endif
4210Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4220Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/*
4250Sstevel@tonic-gate 	 * Check to see if the libsds_sc.so is bound on the
4260Sstevel@tonic-gate 	 * current system. If it is, it means the system is
4270Sstevel@tonic-gate 	 * part of a cluster.
4280Sstevel@tonic-gate 	 *
4290Sstevel@tonic-gate 	 * The import operation is currently not supported
4300Sstevel@tonic-gate 	 * in a SunCluster environment.
4310Sstevel@tonic-gate 	 */
4320Sstevel@tonic-gate 	if (sdssc_bind_library() != SDSSC_NOT_BOUND) {
4330Sstevel@tonic-gate 		printf(gettext(
4340Sstevel@tonic-gate 		    "%s: Import operation not supported under SunCluster\n"),
4350Sstevel@tonic-gate 		    argv[0]);
4360Sstevel@tonic-gate 		exit(0);
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	/* initialize */
4400Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
4410Sstevel@tonic-gate 		mde_perror(ep, "");
4420Sstevel@tonic-gate 		md_exit(sp, 1);
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	optind = 1;
4460Sstevel@tonic-gate 	opterr = 1;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "frns:vV?")) != -1) {
4490Sstevel@tonic-gate 		switch (c) {
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		case 'f':
4520Sstevel@tonic-gate 			force = 1;
4530Sstevel@tonic-gate 			break;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		case 'n':
4560Sstevel@tonic-gate 			dry_run = 1;
4570Sstevel@tonic-gate 			break;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		case 'r':
4600Sstevel@tonic-gate 			report_only = 1;
4610Sstevel@tonic-gate 			break;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		case 's':
4640Sstevel@tonic-gate 			setname_new = optarg;
4650Sstevel@tonic-gate 			break;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		case 'v':
4680Sstevel@tonic-gate 			verbose = 1;
4690Sstevel@tonic-gate 			break;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 		case 'V':
4720Sstevel@tonic-gate 			version = 1;
4730Sstevel@tonic-gate 			break;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 		case '?':
4760Sstevel@tonic-gate 		default:
4770Sstevel@tonic-gate 			usage(sp, NULL);
4780Sstevel@tonic-gate 			break;
4790Sstevel@tonic-gate 		}
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (version == 1)
4830Sstevel@tonic-gate 		print_version(sp);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/* Detect conflicting options */
4860Sstevel@tonic-gate 	if ((dry_run != 0) && (report_only != 0))
4870Sstevel@tonic-gate 		usage(sp, gettext("The -n and -r options conflict."));
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	if ((report_only != 0) && (setname_new != NULL))
4900Sstevel@tonic-gate 		usage(sp, gettext("The -r and -s options conflict."));
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	if ((report_only == 0) && (setname_new == NULL))
4930Sstevel@tonic-gate 		usage(sp, gettext("You must specify either -r or -s."));
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	/* Don't do any real work if we don't have root privilege */
4960Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
4970Sstevel@tonic-gate 		mde_perror(ep, "");
4980Sstevel@tonic-gate 		md_exit(sp, 1);
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
5020Sstevel@tonic-gate 		mde_perror(ep, "");
5030Sstevel@tonic-gate 		if (mdismddberror(ep, MDE_DB_STALE))
5040Sstevel@tonic-gate 			md_exit(sp, 66);
5050Sstevel@tonic-gate 		if (! mdiserror(ep, MDE_MDDB_CKSUM))
5060Sstevel@tonic-gate 			md_exit(sp, 1);
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/*
5100Sstevel@tonic-gate 	 * Read remaining arguments into drive name list, otherwise
5110Sstevel@tonic-gate 	 * call routine to list all drives in system.
5120Sstevel@tonic-gate 	 */
5130Sstevel@tonic-gate 	if (argc > optind) {
5140Sstevel@tonic-gate 		int i;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		/* For user specified disks, they MUST not be in use */
5170Sstevel@tonic-gate 		err_on_prune = 1;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		/* All remaining args should be disks */
5200Sstevel@tonic-gate 		cnames.min_count = argc - optind;
5210Sstevel@tonic-gate 		cnames.min_names = Malloc(cnames.min_count * sizeof (char *));
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 		for (i = 0; i < cnames.min_count; i++, optind++) {
5240Sstevel@tonic-gate 			mddrivename_t *dnp;
5250Sstevel@tonic-gate 			dnp = metadrivename(&sp, argv[optind], ep);
5260Sstevel@tonic-gate 			if (dnp == NULL) {
5270Sstevel@tonic-gate 				mde_perror(ep, "");
5280Sstevel@tonic-gate 				md_exit(sp, 1);
5290Sstevel@tonic-gate 			} else {
5300Sstevel@tonic-gate 				cnames.min_names[i] = dnp->rname;
5310Sstevel@tonic-gate 			}
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 	} else {
5340Sstevel@tonic-gate 		if (meta_list_disks(ep, &cnames) != 0) {
5350Sstevel@tonic-gate 			mde_perror(ep, "");
5360Sstevel@tonic-gate 			md_exit(sp, 1);
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * If the user specified disks on the command line, min_count will be
5420Sstevel@tonic-gate 	 * greater than zero.  If they didn't, it should be safe to assume that
5430Sstevel@tonic-gate 	 * the system in question has at least one drive detected by the
5440Sstevel@tonic-gate 	 * snapshot code, or we would have barfed earlier initializing the
5450Sstevel@tonic-gate 	 * metadb.
5460Sstevel@tonic-gate 	 */
5470Sstevel@tonic-gate 	assert(cnames.min_count > 0);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * Prune the list:
5510Sstevel@tonic-gate 	 * - get rid of drives in current svm configuration
5520Sstevel@tonic-gate 	 * - get rid of mounted drives
5530Sstevel@tonic-gate 	 * - get rid of swap drives
5540Sstevel@tonic-gate 	 * - get rid of drives in other sets
5550Sstevel@tonic-gate 	 *
5560Sstevel@tonic-gate 	 * If drives were specified on the command line, it should be
5570Sstevel@tonic-gate 	 * an error to find in-use disks in the list.  (err_on_prune)
5580Sstevel@tonic-gate 	 *
5590Sstevel@tonic-gate 	 * On return from meta_prune_cnames call, dnlp
5600Sstevel@tonic-gate 	 * will have candidate for replica scan.
5610Sstevel@tonic-gate 	 */
5620Sstevel@tonic-gate 	dnlp = meta_prune_cnames(ep, &cnames, err_on_prune);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	/*
5650Sstevel@tonic-gate 	 * Doctor the drive string in the error structure to list all of the
5660Sstevel@tonic-gate 	 * unused disks, rather than just one.  The output will be done in the
5670Sstevel@tonic-gate 	 * following !mdisok() block.
5680Sstevel@tonic-gate 	 */
5690Sstevel@tonic-gate 	if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) {
5700Sstevel@tonic-gate 		md_ds_error_t		*ip =
5710Sstevel@tonic-gate 		    &ep->info.md_error_info_t_u.ds_error;
5720Sstevel@tonic-gate 		char			*dlist;
5730Sstevel@tonic-gate 		int			sizecnt = 0;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		sizecnt += strlen(ip->drive);
5760Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
5770Sstevel@tonic-gate 			sizecnt += 2; /* for the ", " */
5780Sstevel@tonic-gate 			sizecnt += strlen(dp->drivenamep->cname);
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		dlist = Malloc(sizecnt);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		strlcpy(dlist, ip->drive, sizecnt);
5840Sstevel@tonic-gate 		Free(ip->drive);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 		dlist += strlen(ip->drive);
5870Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
5880Sstevel@tonic-gate 			strlcat(dlist, ", ", sizecnt);
5890Sstevel@tonic-gate 			strlcat(dlist, dp->drivenamep->cname, sizecnt);
5900Sstevel@tonic-gate 		}
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		ip->drive = Strdup(dlist);
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	/* Don't continue if we're already hosed */
5960Sstevel@tonic-gate 	if (!mdisok(ep)) {
5970Sstevel@tonic-gate 		mde_perror(ep, "");
5980Sstevel@tonic-gate 		md_exit(sp, 1);
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/* ...or if there's nothing to scan */
6020Sstevel@tonic-gate 	if (dnlp == NULL) {
6030Sstevel@tonic-gate 		md_eprintf("%s\n", gettext("no unused disks detected"));
6040Sstevel@tonic-gate 		md_exit(sp, 0);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/* Scan qualified disks */
6080Sstevel@tonic-gate 	for (dp = dnlp; dp != NULL; dp = dp->next) {
6090Sstevel@tonic-gate 		mddrivenamelist_t *slp;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 		/* is the current drive on the skip list? */
6120Sstevel@tonic-gate 		for (slp = skiph; slp != NULL; slp = slp->next) {
6130Sstevel@tonic-gate 		    if (dp->drivenamep == slp->drivenamep)
6140Sstevel@tonic-gate 			    goto skipdisk;
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 		hasreplica = meta_get_set_info(dp, mispp, 0, ep);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 		/*
6200Sstevel@tonic-gate 		 * If current disk is part of a partial diskset,
6210Sstevel@tonic-gate 		 * meta_get_set_info returns an ENOTSUP for this disk.
6220Sstevel@tonic-gate 		 * Import of partial disksets isn't supported yet,
6230Sstevel@tonic-gate 		 * so do NOT put this disk onto any list being set up
6240Sstevel@tonic-gate 		 * by metaimport. The partial diskset error message will
6250Sstevel@tonic-gate 		 * only be printed once when the first partial diskset is
6260Sstevel@tonic-gate 		 * detected. If the user is actually trying to import the
6270Sstevel@tonic-gate 		 * partial diskset, print the error and exit; otherwise,
6280Sstevel@tonic-gate 		 * print the error and continue.
6290Sstevel@tonic-gate 		 */
6300Sstevel@tonic-gate 		if (hasreplica == ENOTSUP) {
6310Sstevel@tonic-gate 			if (report_only) {
6320Sstevel@tonic-gate 			    if (!partial) {
6330Sstevel@tonic-gate 				mde_perror(ep, "");
6340Sstevel@tonic-gate 				partial = 1;
6350Sstevel@tonic-gate 			    }
6360Sstevel@tonic-gate 			    mdclrerror(ep);
6370Sstevel@tonic-gate 			    goto skipdisk;
6380Sstevel@tonic-gate 			} else {
6390Sstevel@tonic-gate 			    mde_perror(ep, "");
6400Sstevel@tonic-gate 			    md_exit(sp, 1);
6410Sstevel@tonic-gate 			}
6420Sstevel@tonic-gate 		}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 		if (hasreplica < 0) {
6450Sstevel@tonic-gate 			mde_perror(ep, "");
6460Sstevel@tonic-gate 			mdclrerror(ep);
6470Sstevel@tonic-gate 		} else {
6480Sstevel@tonic-gate 			md_im_set_desc_t	*p;
6490Sstevel@tonic-gate 			md_im_drive_info_t	*d;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 			rscount += hasreplica;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 			/* Eliminate duplicate reporting */
6540Sstevel@tonic-gate 			if (hasreplica > 0) {
6550Sstevel@tonic-gate 				md_timeval32_t	firstdisktime;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 				/*
6580Sstevel@tonic-gate 				 * Go to the tail for the current set
6590Sstevel@tonic-gate 				 */
6600Sstevel@tonic-gate 				for (p = misp; p->mis_next != NULL;
6610Sstevel@tonic-gate 				    p = p->mis_next);
6620Sstevel@tonic-gate 				firstdisktime =
6630Sstevel@tonic-gate 				    p->mis_drives->mid_setcreatetimestamp;
6640Sstevel@tonic-gate 				for (d = p->mis_drives;
6650Sstevel@tonic-gate 				    d != NULL;
6660Sstevel@tonic-gate 				    d = d->mid_next) {
6670Sstevel@tonic-gate 					/*
6680Sstevel@tonic-gate 					 * if the mb_setcreatetime for a disk
6690Sstevel@tonic-gate 					 * is not the same as the first disk
6700Sstevel@tonic-gate 					 * in the set, don't put it on the
6710Sstevel@tonic-gate 					 * skip list. This disk probably
6720Sstevel@tonic-gate 					 * doesn't really belong in this set
6730Sstevel@tonic-gate 					 * and we'll want to look at it again
6740Sstevel@tonic-gate 					 * to figure out where it does belong.
6750Sstevel@tonic-gate 					 */
6760Sstevel@tonic-gate 					if ((d->mid_setcreatetimestamp.tv_sec !=
6770Sstevel@tonic-gate 					    firstdisktime.tv_sec) ||
6780Sstevel@tonic-gate 					    (d->mid_setcreatetimestamp.tv_usec
6790Sstevel@tonic-gate 					    != firstdisktime.tv_usec))
6800Sstevel@tonic-gate 						continue;
6810Sstevel@tonic-gate 					skipt =
6820Sstevel@tonic-gate 					    meta_drivenamelist_append_wrapper(
6830Sstevel@tonic-gate 						skipt, d->mid_dnp);
6840Sstevel@tonic-gate 				}
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 		}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate skipdisk:
6890Sstevel@tonic-gate 		;
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/*
6930Sstevel@tonic-gate 	 * Now have entire list of disks associated with diskset including
6940Sstevel@tonic-gate 	 * disks listed in mddb locator blocks and namespace. Before importing
6950Sstevel@tonic-gate 	 * diskset need to recheck that none of these disks is already in use.
6960Sstevel@tonic-gate 	 * If a disk is found that is already in use, print error and exit.
6970Sstevel@tonic-gate 	 */
6980Sstevel@tonic-gate 	if (!report_only) {
6990Sstevel@tonic-gate 		md_im_set_desc_t	*p;
7000Sstevel@tonic-gate 		md_im_drive_info_t	*d;
7010Sstevel@tonic-gate 		mddrivename_t		*dnp;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		for (p = misp; p != NULL; p = p->mis_next) {
7040Sstevel@tonic-gate 			for (d = p->mis_drives; d != NULL; d = d->mid_next) {
7050Sstevel@tonic-gate 				dnp = d->mid_dnp;
7060Sstevel@tonic-gate 				if (meta_imp_drvused(sp, dnp, ep)) {
7070Sstevel@tonic-gate 					(void) mddserror(ep,
7080Sstevel@tonic-gate 						MDE_DS_DRIVEINUSE, 0, NULL,
7090Sstevel@tonic-gate 						dnp->cname, NULL);
7100Sstevel@tonic-gate 					mde_perror(ep, "");
7110Sstevel@tonic-gate 					md_exit(sp, 0);
7120Sstevel@tonic-gate 				}
7130Sstevel@tonic-gate 			}
7140Sstevel@tonic-gate 		}
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * If there are no unconfigured sets, then our work here is done.
7190Sstevel@tonic-gate 	 * Hopefully this is friendlier than just not printing anything at all.
7200Sstevel@tonic-gate 	 */
7210Sstevel@tonic-gate 	if (rscount == 0) {
722*57Sjeanm 		/*
723*57Sjeanm 		 * If we've found partial disksets but no complete disksets,
724*57Sjeanm 		 * we don't want this to print.
725*57Sjeanm 		 */
726*57Sjeanm 		if (!partial) {
727*57Sjeanm 			md_eprintf("%s\n", gettext("no unconfigured sets "
728*57Sjeanm 			    "detected"));
729*57Sjeanm 		}
7300Sstevel@tonic-gate 		md_exit(sp, 0);
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	/*
7340Sstevel@tonic-gate 	 * We'll need this info for both the report content and the import
7350Sstevel@tonic-gate 	 * decision.  By the time we're here, misp should NOT be NULL (or we
7360Sstevel@tonic-gate 	 * would have exited in the rscount == 0 test above).
7370Sstevel@tonic-gate 	 */
7380Sstevel@tonic-gate 	assert(misp != NULL);
7390Sstevel@tonic-gate 	if (misp->mis_next != NULL) {
7400Sstevel@tonic-gate 		have_multiple_sets = 1;
7410Sstevel@tonic-gate 	}
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	/*
7440Sstevel@tonic-gate 	 * Generate the appropriate (verbose or not) report for all sets
7450Sstevel@tonic-gate 	 * detected.  If we're planning on importing later, only include the
7460Sstevel@tonic-gate 	 * "suggested import" command if multiple sets were detected.  (That
7470Sstevel@tonic-gate 	 * way, when we error out later, we have still provided useful
7480Sstevel@tonic-gate 	 * information.)
7490Sstevel@tonic-gate 	 */
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/*
7520Sstevel@tonic-gate 	 * Now we should have all the unconfigured sets detected
7530Sstevel@tonic-gate 	 * check for the overlapping
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 	if (have_multiple_sets) {
7560Sstevel@tonic-gate 		overlap = set_disk_overlap(misp);
7570Sstevel@tonic-gate 		if (!report_only) {
7580Sstevel@tonic-gate 			md_eprintf("%s\n\n", gettext("multiple unconfigured "
7590Sstevel@tonic-gate 			    "sets detected.\nRerun the command with the "
7600Sstevel@tonic-gate 			    "suggested options for the desired set."));
7610Sstevel@tonic-gate 		}
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	if (verbose) {
7650Sstevel@tonic-gate 	    report_verbose(misp, (report_only || have_multiple_sets), overlap);
7660Sstevel@tonic-gate 	} else {
7670Sstevel@tonic-gate 	    report_standard(misp, (report_only || have_multiple_sets), overlap);
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/*
7710Sstevel@tonic-gate 	 * If it's a report-only request, we're done.  If it's an import
7720Sstevel@tonic-gate 	 * request, make sure that we only have one entry in the set list.
7730Sstevel@tonic-gate 	 */
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	if (report_only) {
7760Sstevel@tonic-gate 		md_exit(sp, 0);
7770Sstevel@tonic-gate 	} else if (have_multiple_sets) {
7780Sstevel@tonic-gate 		md_exit(sp, 1);
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	if (setname_new == NULL) {
7820Sstevel@tonic-gate 		usage(sp, gettext("You must specify a new set name."));
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	(void) meta_imp_set(misp, setname_new, force, dry_run, ep);
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	if (dry_run) {
7880Sstevel@tonic-gate 		md_exit(sp, 0);
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	if (!mdisok(ep)) {
7920Sstevel@tonic-gate 		mde_perror(ep, "");
7930Sstevel@tonic-gate 		md_exit(sp, 1);
7940Sstevel@tonic-gate 	}
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if ((sp = metasetname(setname_new, ep)) == NULL) {
7970Sstevel@tonic-gate 		mde_perror(ep, "");
7980Sstevel@tonic-gate 		md_exit(sp, 1);
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
8020Sstevel@tonic-gate 		mde_perror(ep, "");
8030Sstevel@tonic-gate 		md_exit(sp, 10);	/* special errcode */
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	if (meta_set_take(sp, &mhiargs, 0, 0, &status)) {
8070Sstevel@tonic-gate 		mde_perror(&status, "");
8080Sstevel@tonic-gate 		md_exit(sp, 1);
8090Sstevel@tonic-gate 	}
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	md_exit(sp, 0);
8120Sstevel@tonic-gate 	/*NOTREACHED*/
8130Sstevel@tonic-gate 	return (0);
8140Sstevel@tonic-gate }
815