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 
1840Sstevel@tonic-gate int
1850Sstevel@tonic-gate main(int argc, char *argv[])
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	char			c;
1880Sstevel@tonic-gate 	md_error_t		status = mdnullerror;
1890Sstevel@tonic-gate 	md_error_t		*ep = &status;
1900Sstevel@tonic-gate 	mdsetname_t		*sp = NULL;
1910Sstevel@tonic-gate 	char			*setname_new = NULL;
1920Sstevel@tonic-gate 	int			report_only = 0;
1930Sstevel@tonic-gate 	int			version = 0;
1940Sstevel@tonic-gate 	bool_t			dry_run = 0;
1950Sstevel@tonic-gate 	md_im_names_t		cnames = { 0, NULL };
1960Sstevel@tonic-gate 	int			err_on_prune = 0;
1970Sstevel@tonic-gate 	mddrivenamelist_t	*dnlp = NULL;
1980Sstevel@tonic-gate 	mddrivenamelist_t	*dp;
1990Sstevel@tonic-gate 	mddrivenamelist_t	*skiph = NULL;
2000Sstevel@tonic-gate 	mddrivenamelist_t	**skipt = &skiph;
2010Sstevel@tonic-gate 	int			rscount = 0;
2020Sstevel@tonic-gate 	int			hasreplica;
2030Sstevel@tonic-gate 	md_im_set_desc_t	*misp = NULL;
2040Sstevel@tonic-gate 	md_im_set_desc_t	**mispp = &misp;
2050Sstevel@tonic-gate 	mhd_mhiargs_t		mhiargs = defmhiargs;
2060Sstevel@tonic-gate 	int			have_multiple_sets = 0;
2070Sstevel@tonic-gate 	int			force = 0;
2080Sstevel@tonic-gate 	int			overlap = 0;
2090Sstevel@tonic-gate 	int			partial = 0;
210*734Smw145384 	uint_t			imp_flags = 0;
211*734Smw145384 	int			set_count = 0;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/*
2140Sstevel@tonic-gate 	 * Get the locale set up before calling any other routines
2150Sstevel@tonic-gate 	 * with messages to output.  Just in case we're not in a build
2160Sstevel@tonic-gate 	 * environment, make sure that TEXT_DOMAIN gets set to
2170Sstevel@tonic-gate 	 * something.
2180Sstevel@tonic-gate 	 */
2190Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2200Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
2210Sstevel@tonic-gate #endif
2220Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2230Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/*
2260Sstevel@tonic-gate 	 * Check to see if the libsds_sc.so is bound on the
2270Sstevel@tonic-gate 	 * current system. If it is, it means the system is
2280Sstevel@tonic-gate 	 * part of a cluster.
2290Sstevel@tonic-gate 	 *
2300Sstevel@tonic-gate 	 * The import operation is currently not supported
2310Sstevel@tonic-gate 	 * in a SunCluster environment.
2320Sstevel@tonic-gate 	 */
2330Sstevel@tonic-gate 	if (sdssc_bind_library() != SDSSC_NOT_BOUND) {
2340Sstevel@tonic-gate 		printf(gettext(
2350Sstevel@tonic-gate 		    "%s: Import operation not supported under SunCluster\n"),
2360Sstevel@tonic-gate 		    argv[0]);
2370Sstevel@tonic-gate 		exit(0);
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/* initialize */
2410Sstevel@tonic-gate 	if (md_init(argc, argv, 0, 1, ep) != 0) {
2420Sstevel@tonic-gate 		mde_perror(ep, "");
2430Sstevel@tonic-gate 		md_exit(sp, 1);
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	optind = 1;
2470Sstevel@tonic-gate 	opterr = 1;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "frns:vV?")) != -1) {
2500Sstevel@tonic-gate 		switch (c) {
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		case 'f':
2530Sstevel@tonic-gate 			force = 1;
2540Sstevel@tonic-gate 			break;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		case 'n':
2570Sstevel@tonic-gate 			dry_run = 1;
2580Sstevel@tonic-gate 			break;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		case 'r':
2610Sstevel@tonic-gate 			report_only = 1;
262*734Smw145384 			imp_flags |= META_IMP_REPORT;
2630Sstevel@tonic-gate 			break;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		case 's':
2660Sstevel@tonic-gate 			setname_new = optarg;
2670Sstevel@tonic-gate 			break;
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 		case 'v':
270*734Smw145384 			imp_flags |= META_IMP_VERBOSE;
2710Sstevel@tonic-gate 			break;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		case 'V':
2740Sstevel@tonic-gate 			version = 1;
2750Sstevel@tonic-gate 			break;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		case '?':
2780Sstevel@tonic-gate 		default:
2790Sstevel@tonic-gate 			usage(sp, NULL);
2800Sstevel@tonic-gate 			break;
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (version == 1)
2850Sstevel@tonic-gate 		print_version(sp);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/* Detect conflicting options */
2880Sstevel@tonic-gate 	if ((dry_run != 0) && (report_only != 0))
2890Sstevel@tonic-gate 		usage(sp, gettext("The -n and -r options conflict."));
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	if ((report_only != 0) && (setname_new != NULL))
2920Sstevel@tonic-gate 		usage(sp, gettext("The -r and -s options conflict."));
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if ((report_only == 0) && (setname_new == NULL))
2950Sstevel@tonic-gate 		usage(sp, gettext("You must specify either -r or -s."));
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/* Don't do any real work if we don't have root privilege */
2980Sstevel@tonic-gate 	if (meta_check_root(ep) != 0) {
2990Sstevel@tonic-gate 		mde_perror(ep, "");
3000Sstevel@tonic-gate 		md_exit(sp, 1);
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (meta_setup_db_locations(ep) != 0) {
3040Sstevel@tonic-gate 		mde_perror(ep, "");
3050Sstevel@tonic-gate 		if (mdismddberror(ep, MDE_DB_STALE))
3060Sstevel@tonic-gate 			md_exit(sp, 66);
3070Sstevel@tonic-gate 		if (! mdiserror(ep, MDE_MDDB_CKSUM))
3080Sstevel@tonic-gate 			md_exit(sp, 1);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	/*
3120Sstevel@tonic-gate 	 * Read remaining arguments into drive name list, otherwise
3130Sstevel@tonic-gate 	 * call routine to list all drives in system.
3140Sstevel@tonic-gate 	 */
3150Sstevel@tonic-gate 	if (argc > optind) {
3160Sstevel@tonic-gate 		int i;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		/* For user specified disks, they MUST not be in use */
3190Sstevel@tonic-gate 		err_on_prune = 1;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		/* All remaining args should be disks */
3220Sstevel@tonic-gate 		cnames.min_count = argc - optind;
3230Sstevel@tonic-gate 		cnames.min_names = Malloc(cnames.min_count * sizeof (char *));
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		for (i = 0; i < cnames.min_count; i++, optind++) {
3260Sstevel@tonic-gate 			mddrivename_t *dnp;
3270Sstevel@tonic-gate 			dnp = metadrivename(&sp, argv[optind], ep);
3280Sstevel@tonic-gate 			if (dnp == NULL) {
3290Sstevel@tonic-gate 				mde_perror(ep, "");
3300Sstevel@tonic-gate 				md_exit(sp, 1);
3310Sstevel@tonic-gate 			} else {
3320Sstevel@tonic-gate 				cnames.min_names[i] = dnp->rname;
3330Sstevel@tonic-gate 			}
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 	} else {
3360Sstevel@tonic-gate 		if (meta_list_disks(ep, &cnames) != 0) {
3370Sstevel@tonic-gate 			mde_perror(ep, "");
3380Sstevel@tonic-gate 			md_exit(sp, 1);
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/*
3430Sstevel@tonic-gate 	 * If the user specified disks on the command line, min_count will be
3440Sstevel@tonic-gate 	 * greater than zero.  If they didn't, it should be safe to assume that
3450Sstevel@tonic-gate 	 * the system in question has at least one drive detected by the
3460Sstevel@tonic-gate 	 * snapshot code, or we would have barfed earlier initializing the
3470Sstevel@tonic-gate 	 * metadb.
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 	assert(cnames.min_count > 0);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	/*
3520Sstevel@tonic-gate 	 * Prune the list:
3530Sstevel@tonic-gate 	 * - get rid of drives in current svm configuration
3540Sstevel@tonic-gate 	 * - get rid of mounted drives
3550Sstevel@tonic-gate 	 * - get rid of swap drives
3560Sstevel@tonic-gate 	 * - get rid of drives in other sets
3570Sstevel@tonic-gate 	 *
3580Sstevel@tonic-gate 	 * If drives were specified on the command line, it should be
3590Sstevel@tonic-gate 	 * an error to find in-use disks in the list.  (err_on_prune)
3600Sstevel@tonic-gate 	 *
3610Sstevel@tonic-gate 	 * On return from meta_prune_cnames call, dnlp
3620Sstevel@tonic-gate 	 * will have candidate for replica scan.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	dnlp = meta_prune_cnames(ep, &cnames, err_on_prune);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/*
3670Sstevel@tonic-gate 	 * Doctor the drive string in the error structure to list all of the
3680Sstevel@tonic-gate 	 * unused disks, rather than just one.  The output will be done in the
3690Sstevel@tonic-gate 	 * following !mdisok() block.
3700Sstevel@tonic-gate 	 */
3710Sstevel@tonic-gate 	if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) {
3720Sstevel@tonic-gate 		md_ds_error_t		*ip =
3730Sstevel@tonic-gate 		    &ep->info.md_error_info_t_u.ds_error;
3740Sstevel@tonic-gate 		char			*dlist;
3750Sstevel@tonic-gate 		int			sizecnt = 0;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		sizecnt += strlen(ip->drive);
3780Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
3790Sstevel@tonic-gate 			sizecnt += 2; /* for the ", " */
3800Sstevel@tonic-gate 			sizecnt += strlen(dp->drivenamep->cname);
3810Sstevel@tonic-gate 		}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 		dlist = Malloc(sizecnt);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 		strlcpy(dlist, ip->drive, sizecnt);
3860Sstevel@tonic-gate 		Free(ip->drive);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		dlist += strlen(ip->drive);
3890Sstevel@tonic-gate 		for (dp = dnlp->next; dp != NULL; dp = dp->next) {
3900Sstevel@tonic-gate 			strlcat(dlist, ", ", sizecnt);
3910Sstevel@tonic-gate 			strlcat(dlist, dp->drivenamep->cname, sizecnt);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		ip->drive = Strdup(dlist);
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/* Don't continue if we're already hosed */
3980Sstevel@tonic-gate 	if (!mdisok(ep)) {
3990Sstevel@tonic-gate 		mde_perror(ep, "");
4000Sstevel@tonic-gate 		md_exit(sp, 1);
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	/* ...or if there's nothing to scan */
4040Sstevel@tonic-gate 	if (dnlp == NULL) {
4050Sstevel@tonic-gate 		md_eprintf("%s\n", gettext("no unused disks detected"));
4060Sstevel@tonic-gate 		md_exit(sp, 0);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/* Scan qualified disks */
4100Sstevel@tonic-gate 	for (dp = dnlp; dp != NULL; dp = dp->next) {
4110Sstevel@tonic-gate 		mddrivenamelist_t *slp;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 		/* is the current drive on the skip list? */
4140Sstevel@tonic-gate 		for (slp = skiph; slp != NULL; slp = slp->next) {
4150Sstevel@tonic-gate 		    if (dp->drivenamep == slp->drivenamep)
4160Sstevel@tonic-gate 			    goto skipdisk;
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 
419*734Smw145384 		/*
420*734Smw145384 		 * In addition to updating the misp list, either verbose or
421*734Smw145384 		 * standard output will be generated.
422*734Smw145384 		 *
423*734Smw145384 		 */
424*734Smw145384 		hasreplica = meta_get_and_report_set_info(dp, mispp, 0,
425*734Smw145384 		    imp_flags, &set_count, ep);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		/*
4280Sstevel@tonic-gate 		 * If current disk is part of a partial diskset,
4290Sstevel@tonic-gate 		 * meta_get_set_info returns an ENOTSUP for this disk.
4300Sstevel@tonic-gate 		 * Import of partial disksets isn't supported yet,
4310Sstevel@tonic-gate 		 * so do NOT put this disk onto any list being set up
4320Sstevel@tonic-gate 		 * by metaimport. The partial diskset error message will
4330Sstevel@tonic-gate 		 * only be printed once when the first partial diskset is
4340Sstevel@tonic-gate 		 * detected. If the user is actually trying to import the
4350Sstevel@tonic-gate 		 * partial diskset, print the error and exit; otherwise,
4360Sstevel@tonic-gate 		 * print the error and continue.
4370Sstevel@tonic-gate 		 */
4380Sstevel@tonic-gate 		if (hasreplica == ENOTSUP) {
4390Sstevel@tonic-gate 			if (report_only) {
4400Sstevel@tonic-gate 			    if (!partial) {
4410Sstevel@tonic-gate 				mde_perror(ep, "");
4420Sstevel@tonic-gate 				partial = 1;
4430Sstevel@tonic-gate 			    }
4440Sstevel@tonic-gate 			    mdclrerror(ep);
4450Sstevel@tonic-gate 			    goto skipdisk;
4460Sstevel@tonic-gate 			} else {
4470Sstevel@tonic-gate 			    mde_perror(ep, "");
4480Sstevel@tonic-gate 			    md_exit(sp, 1);
4490Sstevel@tonic-gate 			}
4500Sstevel@tonic-gate 		}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		if (hasreplica < 0) {
4530Sstevel@tonic-gate 			mde_perror(ep, "");
4540Sstevel@tonic-gate 			mdclrerror(ep);
4550Sstevel@tonic-gate 		} else {
4560Sstevel@tonic-gate 			md_im_set_desc_t	*p;
4570Sstevel@tonic-gate 			md_im_drive_info_t	*d;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 			rscount += hasreplica;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 			/* Eliminate duplicate reporting */
4620Sstevel@tonic-gate 			if (hasreplica > 0) {
4630Sstevel@tonic-gate 				md_timeval32_t	firstdisktime;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 				/*
4660Sstevel@tonic-gate 				 * Go to the tail for the current set
4670Sstevel@tonic-gate 				 */
4680Sstevel@tonic-gate 				for (p = misp; p->mis_next != NULL;
4690Sstevel@tonic-gate 				    p = p->mis_next);
4700Sstevel@tonic-gate 				firstdisktime =
4710Sstevel@tonic-gate 				    p->mis_drives->mid_setcreatetimestamp;
4720Sstevel@tonic-gate 				for (d = p->mis_drives;
4730Sstevel@tonic-gate 				    d != NULL;
4740Sstevel@tonic-gate 				    d = d->mid_next) {
4750Sstevel@tonic-gate 					/*
4760Sstevel@tonic-gate 					 * if the mb_setcreatetime for a disk
4770Sstevel@tonic-gate 					 * is not the same as the first disk
4780Sstevel@tonic-gate 					 * in the set, don't put it on the
4790Sstevel@tonic-gate 					 * skip list. This disk probably
4800Sstevel@tonic-gate 					 * doesn't really belong in this set
4810Sstevel@tonic-gate 					 * and we'll want to look at it again
4820Sstevel@tonic-gate 					 * to figure out where it does belong.
4830Sstevel@tonic-gate 					 */
4840Sstevel@tonic-gate 					if ((d->mid_setcreatetimestamp.tv_sec !=
4850Sstevel@tonic-gate 					    firstdisktime.tv_sec) ||
4860Sstevel@tonic-gate 					    (d->mid_setcreatetimestamp.tv_usec
4870Sstevel@tonic-gate 					    != firstdisktime.tv_usec))
4880Sstevel@tonic-gate 						continue;
4890Sstevel@tonic-gate 					skipt =
4900Sstevel@tonic-gate 					    meta_drivenamelist_append_wrapper(
4910Sstevel@tonic-gate 						skipt, d->mid_dnp);
4920Sstevel@tonic-gate 				}
4930Sstevel@tonic-gate 			}
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate skipdisk:
4970Sstevel@tonic-gate 		;
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	/*
5010Sstevel@tonic-gate 	 * Now have entire list of disks associated with diskset including
5020Sstevel@tonic-gate 	 * disks listed in mddb locator blocks and namespace. Before importing
5030Sstevel@tonic-gate 	 * diskset need to recheck that none of these disks is already in use.
5040Sstevel@tonic-gate 	 * If a disk is found that is already in use, print error and exit.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	if (!report_only) {
5070Sstevel@tonic-gate 		md_im_set_desc_t	*p;
5080Sstevel@tonic-gate 		md_im_drive_info_t	*d;
5090Sstevel@tonic-gate 		mddrivename_t		*dnp;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 		for (p = misp; p != NULL; p = p->mis_next) {
5120Sstevel@tonic-gate 			for (d = p->mis_drives; d != NULL; d = d->mid_next) {
5130Sstevel@tonic-gate 				dnp = d->mid_dnp;
5140Sstevel@tonic-gate 				if (meta_imp_drvused(sp, dnp, ep)) {
5150Sstevel@tonic-gate 					(void) mddserror(ep,
5160Sstevel@tonic-gate 						MDE_DS_DRIVEINUSE, 0, NULL,
5170Sstevel@tonic-gate 						dnp->cname, NULL);
5180Sstevel@tonic-gate 					mde_perror(ep, "");
5190Sstevel@tonic-gate 					md_exit(sp, 0);
5200Sstevel@tonic-gate 				}
5210Sstevel@tonic-gate 			}
5220Sstevel@tonic-gate 		}
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	/*
5260Sstevel@tonic-gate 	 * If there are no unconfigured sets, then our work here is done.
5270Sstevel@tonic-gate 	 * Hopefully this is friendlier than just not printing anything at all.
5280Sstevel@tonic-gate 	 */
5290Sstevel@tonic-gate 	if (rscount == 0) {
53057Sjeanm 		/*
53157Sjeanm 		 * If we've found partial disksets but no complete disksets,
53257Sjeanm 		 * we don't want this to print.
53357Sjeanm 		 */
53457Sjeanm 		if (!partial) {
53557Sjeanm 			md_eprintf("%s\n", gettext("no unconfigured sets "
53657Sjeanm 			    "detected"));
53757Sjeanm 		}
5380Sstevel@tonic-gate 		md_exit(sp, 0);
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	/*
5420Sstevel@tonic-gate 	 * We'll need this info for both the report content and the import
5430Sstevel@tonic-gate 	 * decision.  By the time we're here, misp should NOT be NULL (or we
5440Sstevel@tonic-gate 	 * would have exited in the rscount == 0 test above).
5450Sstevel@tonic-gate 	 */
5460Sstevel@tonic-gate 	assert(misp != NULL);
5470Sstevel@tonic-gate 	if (misp->mis_next != NULL) {
5480Sstevel@tonic-gate 		have_multiple_sets = 1;
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 	/*
5510Sstevel@tonic-gate 	 * Generate the appropriate (verbose or not) report for all sets
5520Sstevel@tonic-gate 	 * detected.  If we're planning on importing later, only include the
5530Sstevel@tonic-gate 	 * "suggested import" command if multiple sets were detected.  (That
5540Sstevel@tonic-gate 	 * way, when we error out later, we have still provided useful
5550Sstevel@tonic-gate 	 * information.)
5560Sstevel@tonic-gate 	 */
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	/*
5590Sstevel@tonic-gate 	 * Now we should have all the unconfigured sets detected
5600Sstevel@tonic-gate 	 * check for the overlapping
5610Sstevel@tonic-gate 	 */
5620Sstevel@tonic-gate 	if (have_multiple_sets) {
563*734Smw145384 		/* Printing out how many candidate disksets we found. */
564*734Smw145384 		if (imp_flags & META_IMP_REPORT) {
565*734Smw145384 			(void) printf("%s: %i\n\n",
566*734Smw145384 			    gettext("Number of disksets eligible for import"),
567*734Smw145384 			    set_count);
568*734Smw145384 		}
569*734Smw145384 
5700Sstevel@tonic-gate 		overlap = set_disk_overlap(misp);
571*734Smw145384 		if (overlap) {
572*734Smw145384 			report_overlap_recommendation();
573*734Smw145384 		}
574*734Smw145384 
5750Sstevel@tonic-gate 		if (!report_only) {
5760Sstevel@tonic-gate 			md_eprintf("%s\n\n", gettext("multiple unconfigured "
5770Sstevel@tonic-gate 			    "sets detected.\nRerun the command with the "
5780Sstevel@tonic-gate 			    "suggested options for the desired set."));
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	/*
5840Sstevel@tonic-gate 	 * If it's a report-only request, we're done.  If it's an import
5850Sstevel@tonic-gate 	 * request, make sure that we only have one entry in the set list.
5860Sstevel@tonic-gate 	 */
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	if (report_only) {
5890Sstevel@tonic-gate 		md_exit(sp, 0);
5900Sstevel@tonic-gate 	} else if (have_multiple_sets) {
5910Sstevel@tonic-gate 		md_exit(sp, 1);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	if (setname_new == NULL) {
5950Sstevel@tonic-gate 		usage(sp, gettext("You must specify a new set name."));
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	(void) meta_imp_set(misp, setname_new, force, dry_run, ep);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (dry_run) {
6010Sstevel@tonic-gate 		md_exit(sp, 0);
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (!mdisok(ep)) {
6050Sstevel@tonic-gate 		mde_perror(ep, "");
6060Sstevel@tonic-gate 		md_exit(sp, 1);
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if ((sp = metasetname(setname_new, ep)) == NULL) {
6100Sstevel@tonic-gate 		mde_perror(ep, "");
6110Sstevel@tonic-gate 		md_exit(sp, 1);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	if (meta_lock_nowait(sp, ep) != 0) {
6150Sstevel@tonic-gate 		mde_perror(ep, "");
6160Sstevel@tonic-gate 		md_exit(sp, 10);	/* special errcode */
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	if (meta_set_take(sp, &mhiargs, 0, 0, &status)) {
6200Sstevel@tonic-gate 		mde_perror(&status, "");
6210Sstevel@tonic-gate 		md_exit(sp, 1);
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	md_exit(sp, 0);
6250Sstevel@tonic-gate 	/*NOTREACHED*/
6260Sstevel@tonic-gate 	return (0);
6270Sstevel@tonic-gate }
628